summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:19:49 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:19:49 +0200
commitc8e0e909b4a8d18319fc65434a10dc446434817c (patch)
treeeee91e7d2ce229dd043811eae8f1e2bd78061916
parent5.2 (diff)
downloadFreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.gz
FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.bz2
FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.zip
5.3
-rw-r--r--Application.cpp66
-rw-r--r--BUILD/Changelog.txt27
-rw-r--r--BUILD/FreeFileSync.chmbin663884 -> 663954 bytes
-rw-r--r--BUILD/Help/html/FreeFileSync.html4
-rw-r--r--BUILD/Languages/chinese_simple.lng251
-rw-r--r--BUILD/Languages/chinese_traditional.lng265
-rw-r--r--BUILD/Languages/croatian.lng247
-rw-r--r--BUILD/Languages/czech.lng247
-rw-r--r--BUILD/Languages/danish.lng251
-rw-r--r--BUILD/Languages/dutch.lng263
-rw-r--r--BUILD/Languages/english_uk.lng248
-rw-r--r--BUILD/Languages/finnish.lng357
-rw-r--r--BUILD/Languages/french.lng249
-rw-r--r--BUILD/Languages/german.lng253
-rw-r--r--BUILD/Languages/greek.lng249
-rw-r--r--BUILD/Languages/hebrew.lng261
-rw-r--r--BUILD/Languages/hungarian.lng261
-rw-r--r--BUILD/Languages/italian.lng265
-rw-r--r--BUILD/Languages/japanese.lng251
-rw-r--r--BUILD/Languages/korean.lng269
-rw-r--r--BUILD/Languages/lithuanian.lng1487
-rw-r--r--BUILD/Languages/norwegian.lng1463
-rw-r--r--BUILD/Languages/polish.lng318
-rw-r--r--BUILD/Languages/portuguese.lng291
-rw-r--r--BUILD/Languages/portuguese_br.lng265
-rw-r--r--BUILD/Languages/romanian.lng250
-rw-r--r--BUILD/Languages/russian.lng253
-rw-r--r--BUILD/Languages/slovenian.lng251
-rw-r--r--BUILD/Languages/spanish.lng263
-rw-r--r--BUILD/Languages/swedish.lng251
-rw-r--r--BUILD/Languages/turkish.lng247
-rw-r--r--BUILD/Languages/ukrainian.lng261
-rw-r--r--BUILD/Resources.zipbin271346 -> 272579 bytes
-rw-r--r--BUILD/styles.rc4
-rw-r--r--FreeFileSync.cbp16
-rw-r--r--FreeFileSync.vcxproj63
-rw-r--r--Makefile4
-rw-r--r--RealtimeSync/RealtimeSync.cbp2
-rw-r--r--RealtimeSync/RealtimeSync.vcxproj59
-rw-r--r--RealtimeSync/application.cpp24
-rw-r--r--RealtimeSync/gui_generated.cpp66
-rw-r--r--RealtimeSync/gui_generated.h30
-rw-r--r--RealtimeSync/main_dlg.cpp109
-rw-r--r--RealtimeSync/main_dlg.h22
-rw-r--r--RealtimeSync/resources.cpp12
-rw-r--r--RealtimeSync/tray_menu.cpp479
-rw-r--r--RealtimeSync/tray_menu.h9
-rw-r--r--RealtimeSync/watcher.cpp138
-rw-r--r--RealtimeSync/watcher.h16
-rw-r--r--RealtimeSync/xml_ffs.cpp6
-rw-r--r--RealtimeSync/xml_ffs.h3
-rw-r--r--RealtimeSync/xml_proc.cpp16
-rw-r--r--RealtimeSync/xml_proc.h5
-rw-r--r--algorithm.cpp77
-rw-r--r--comparison.cpp73
-rw-r--r--comparison.h2
-rw-r--r--file_hierarchy.cpp9
-rw-r--r--file_hierarchy.h20
-rw-r--r--lib/IFileOperation/file_op.cpp190
-rw-r--r--lib/ShadowCopy/LockFile.cpp5
-rw-r--r--lib/ShadowCopy/Shadow_Server2003.vcxproj12
-rw-r--r--lib/ShadowCopy/Shadow_Windows7.vcxproj12
-rw-r--r--lib/ShadowCopy/Shadow_XP.vcxproj12
-rw-r--r--lib/ShadowCopy/shadow.cpp36
-rw-r--r--lib/ShadowCopy/shadow.h35
-rw-r--r--lib/Thumbnail/thumbnail.cpp28
-rw-r--r--lib/Thumbnail/thumbnail.h8
-rw-r--r--lib/binary.cpp4
-rw-r--r--lib/binary.h2
-rw-r--r--lib/db_file.cpp34
-rw-r--r--lib/dir_exist_async.h5
-rw-r--r--lib/dir_lock.cpp407
-rw-r--r--lib/dir_lock.h8
-rw-r--r--lib/ffs_paths.h14
-rw-r--r--lib/icon_buffer.cpp27
-rw-r--r--lib/localization.cpp16
-rw-r--r--lib/parallel_scan.cpp21
-rw-r--r--lib/parse_plural.h2
-rw-r--r--lib/perf_check.cpp (renamed from lib/statistics.cpp)140
-rw-r--r--lib/perf_check.h40
-rw-r--r--lib/process_xml.cpp104
-rw-r--r--lib/process_xml.h26
-rw-r--r--lib/recycler.cpp210
-rw-r--r--lib/resolve_path.cpp241
-rw-r--r--lib/resources.cpp14
-rw-r--r--lib/shadow.cpp69
-rw-r--r--lib/shadow.h2
-rw-r--r--lib/statistics.h73
-rw-r--r--lib/status_handler.cpp22
-rw-r--r--lib/status_handler.h102
-rw-r--r--lib/status_handler_impl.h2
-rw-r--r--lib/xml_base.cpp18
-rw-r--r--process_callback.h27
-rw-r--r--structures.cpp2
-rw-r--r--structures.h6
-rw-r--r--synchronization.cpp209
-rw-r--r--synchronization.h2
-rw-r--r--ui/batch_config.cpp128
-rw-r--r--ui/batch_config.h5
-rw-r--r--ui/batch_status_handler.cpp200
-rw-r--r--ui/batch_status_handler.h12
-rw-r--r--ui/check_version.cpp22
-rw-r--r--ui/check_version.h6
-rw-r--r--ui/custom_grid.cpp34
-rw-r--r--ui/exec_finished_box.cpp3
-rw-r--r--ui/folder_history_box.cpp8
-rw-r--r--ui/folder_pair.h8
-rw-r--r--ui/grid_view.cpp15
-rw-r--r--ui/grid_view.h12
-rw-r--r--ui/gui_generated.cpp139
-rw-r--r--ui/gui_generated.h18
-rw-r--r--ui/gui_status_handler.cpp238
-rw-r--r--ui/gui_status_handler.h19
-rw-r--r--ui/main_dlg.cpp521
-rw-r--r--ui/main_dlg.h1
-rw-r--r--ui/msg_popup.cpp34
-rw-r--r--ui/msg_popup.h11
-rw-r--r--ui/progress_indicator.cpp1168
-rw-r--r--ui/progress_indicator.h43
-rw-r--r--ui/search.cpp36
-rw-r--r--ui/search.h4
-rw-r--r--ui/small_dlgs.cpp103
-rw-r--r--ui/small_dlgs.h31
-rw-r--r--ui/sorting.h17
-rw-r--r--ui/sync_cfg.cpp17
-rw-r--r--ui/sync_cfg.h7
-rw-r--r--ui/taskbar.cpp4
-rw-r--r--ui/taskbar.h2
-rw-r--r--ui/tray_icon.cpp22
-rw-r--r--ui/tray_icon.h6
-rw-r--r--ui/tree_view.cpp8
-rw-r--r--ui/tree_view.h2
-rw-r--r--version/version.h2
-rw-r--r--version/version.rc4
-rw-r--r--wx+/context_menu.h40
-rw-r--r--wx+/graph.cpp3
-rw-r--r--wx+/grid.cpp21
-rw-r--r--wx+/serialize.h109
-rw-r--r--wx+/shell_execute.h36
-rw-r--r--wx+/string_conv.h8
-rw-r--r--wx+/toggle_button.h8
-rw-r--r--wxWidgets-Fix/apply-patches.cmd5
-rw-r--r--wxWidgets-Fix/settings.cpp.patch60
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp2
-rw-r--r--zen/FindFilePlus/find_file_plus.h16
-rw-r--r--zen/IFileOperation/FileOperation_Vista.vcxproj (renamed from lib/IFileOperation/FileOperation_Vista.vcxproj)12
-rw-r--r--zen/IFileOperation/dll_main.cpp (renamed from lib/IFileOperation/dll_main.cpp)0
-rw-r--r--zen/IFileOperation/file_op.cpp349
-rw-r--r--zen/IFileOperation/file_op.h (renamed from lib/IFileOperation/file_op.h)34
-rw-r--r--zen/com_error.h11
-rw-r--r--zen/dir_watcher.cpp65
-rw-r--r--zen/dst_hack.cpp17
-rw-r--r--zen/dst_hack.h8
-rw-r--r--zen/file_error.h15
-rw-r--r--zen/file_handling.cpp1400
-rw-r--r--zen/file_handling.h14
-rw-r--r--zen/file_io.cpp21
-rw-r--r--zen/file_traverser.cpp81
-rw-r--r--zen/file_update_handle.h4
-rw-r--r--zen/guid.h3
-rw-r--r--zen/long_path_prefix.h2
-rw-r--r--zen/notify_removal.cpp45
-rw-r--r--zen/perf.h100
-rw-r--r--zen/privilege.cpp14
-rw-r--r--zen/process_priority.h (renamed from zen/process_status.h)0
-rw-r--r--zen/recycler.cpp280
-rw-r--r--zen/recycler.h (renamed from lib/recycler.h)2
-rw-r--r--zen/stl_tools.h1
-rw-r--r--zen/string_base.h8
-rw-r--r--zen/string_tools.h105
-rw-r--r--zen/symlink_target.h8
-rw-r--r--zen/thread.h119
-rw-r--r--zen/tick_count.h114
-rw-r--r--zen/time.h6
-rw-r--r--zen/win_ver.h24
-rw-r--r--zen/zstring.cpp2
-rw-r--r--zen/zstring.h17
177 files changed, 11164 insertions, 8270 deletions
diff --git a/Application.cpp b/Application.cpp
index 5b6fa2d8..899c86c8 100644
--- a/Application.cpp
+++ b/Application.cpp
@@ -45,7 +45,7 @@ void onTerminationRequested()
std::wstring msg = ::GetCurrentThreadId() == mainThreadId ?
L"Termination requested in main thread!\n\n" :
L"Termination requested in worker thread!\n\n";
- msg += L"Please take a screenshot and file a bug report on: http://sourceforge.net/projects/freefilesync";
+ msg += L"Please take a screenshot and file a bug report at: http://sourceforge.net/projects/freefilesync";
::MessageBox(0, msg.c_str(), _("An exception occurred!").c_str(), 0);
std::abort();
@@ -77,13 +77,13 @@ void Application::OnStartApplication(wxIdleEvent&)
{
Disconnect(wxEVT_IDLE, wxIdleEventHandler(Application::OnStartApplication), nullptr, this);
- //wxWidgets app exit handling is quite weird... we want the app to exit only if the logical main window is closed
+ //wxWidgets app exit handling is weird... we want the app to exit only if the logical main window is closed
wxTheApp->SetExitOnFrameDelete(false); //avoid popup-windows from becoming temporary top windows leading to program exit after closure
- wxApp* app = wxTheApp;
+ auto app = wxTheApp; //fix lambda/wxWigets/VC fuck up
ZEN_ON_SCOPE_EXIT(if (!mainWindowWasSet()) app->ExitMainLoop();); //quit application, if no main window was set (batch silent mode)
//if appname is not set, the default is the executable's name!
- SetAppName(wxT("FreeFileSync"));
+ SetAppName(L"FreeFileSync");
#ifdef FFS_WIN
//Quote: "Best practice is that all applications call the process-wide SetErrorMode function with a parameter of
@@ -91,12 +91,10 @@ void Application::OnStartApplication(wxIdleEvent&)
::SetErrorMode(SEM_FAILCRITICALERRORS);
#elif defined FFS_LINUX
- gtk_init(nullptr, nullptr);
-
+ ::gtk_init(nullptr, nullptr);
::gtk_rc_parse((getResourceDir() + "styles.rc").c_str()); //remove inner border from bitmap buttons
#endif
-
#if wxCHECK_VERSION(2, 9, 1)
#ifdef FFS_WIN
wxToolTip::SetMaxWidth(-1); //disable tooltip wrapping -> Windows only (as of 2.9.2)
@@ -104,7 +102,6 @@ void Application::OnStartApplication(wxIdleEvent&)
wxToolTip::SetAutoPop(7000); //tooltip visibilty in ms, 5s seems to be default for Windows
#endif
-
try //load global settings from XML: they are written on exit, so read them FIRST
{
if (fileExists(toZ(getGlobalConfigFile())))
@@ -123,7 +120,6 @@ void Application::OnStartApplication(wxIdleEvent&)
//set program language
setLanguage(globalSettings.programLanguage);
-
//determine FFS mode of operation
std::vector<wxString> commandArgs; //wxWidgets screws up once again making "argv implicitly convertible to a wxChar**" in 2.9.3,
for (int i = 1; i < argc; ++i) //so we are forced to use this pitiful excuse for a range construction!!
@@ -142,7 +138,6 @@ void Application::OnStartApplication(wxIdleEvent&)
for (auto iter = commandArgs.begin(); iter != commandArgs.end(); ++iter)
{
size_t index = iter - commandArgs.begin();
- Zstring dirname = toZ(*iter);
FolderPairEnh& fp = [&]() -> FolderPairEnh&
{
@@ -154,9 +149,9 @@ void Application::OnStartApplication(wxIdleEvent&)
}();
if (index % 2 == 0)
- fp.leftDirectory = dirname;
+ fp.leftDirectory = toZ(*iter);
else if (index % 2 == 1)
- fp.rightDirectory = dirname;
+ fp.rightDirectory = toZ(*iter);
}
runGuiMode(guiCfg, globalSettings);
@@ -165,23 +160,23 @@ void Application::OnStartApplication(wxIdleEvent&)
{
for (auto iter = commandArgs.begin(); iter != commandArgs.end(); ++iter)
{
- wxString& filename = *iter;
+ const Zstring& filename = toZ(*iter);
- if (!fileExists(toZ(filename))) //be a little tolerant
+ if (!fileExists(filename)) //be a little tolerant
{
- if (fileExists(toZ(filename) + Zstr(".ffs_batch")))
- filename += L".ffs_batch";
- else if (fileExists(toZ(filename) + Zstr(".ffs_gui")))
- filename += L".ffs_gui";
+ if (fileExists(filename + Zstr(".ffs_batch")))
+ *iter += L".ffs_batch";
+ else if (fileExists(filename + Zstr(".ffs_gui")))
+ *iter += L".ffs_gui";
else
{
- wxMessageBox(_("File does not exist:") + L" \"" + filename + L"\"", _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)), _("Error"), wxOK | wxICON_ERROR);
return;
}
}
}
- switch (getMergeType(commandArgs)) //throw ()
+ switch (getMergeType(toZ(commandArgs))) //throw ()
{
case MERGE_BATCH: //pure batch config files
if (commandArgs.size() == 1)
@@ -200,11 +195,11 @@ void Application::OnStartApplication(wxIdleEvent&)
std::find_if(commandArgs.begin(), commandArgs.end(),
[](const wxString& filename) -> bool
{
- switch (getXmlType(filename)) //throw()
+ switch (getXmlType(toZ(filename))) //throw()
{
case XML_TYPE_GLOBAL:
case XML_TYPE_OTHER:
- wxMessageBox(wxString(_("The file does not contain a valid configuration:")) + wxT(" \"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(_("The file does not contain a valid configuration:") + L" " + fmtFileName(toZ(filename)), _("Error"), wxOK | wxICON_ERROR);
return true;
case XML_TYPE_GUI:
@@ -234,7 +229,7 @@ int Application::OnRun()
}
catch (const std::exception& e) //catch all STL exceptions
{
- //unfortunately it's not always possible to display a message box in this erroneous situation, however (non-stream) file output always works!
+ //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(utf8CvrtTo<wxString>(e.what()));
@@ -243,10 +238,12 @@ int Application::OnRun()
}
catch (...) //catch the rest
{
+ const wxString& msg = L"Unknown error.";
+
wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write);
- safeOutput.Write(wxT("Unknown exception!"));
+ safeOutput.Write(msg);
- wxSafeShowMessage(_("An exception occurred!"), L"Unknown exception!");
+ wxSafeShowMessage(_("An exception occurred!"), msg);
return -9;
}
@@ -306,7 +303,7 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet
XmlBatchConfig batchCfg; //structure to receive gui settings
try
{
- readConfig(filename, batchCfg);
+ readConfig(toZ(filename), batchCfg);
}
catch (const xmlAccess::FfsXmlError& error)
{
@@ -348,13 +345,18 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet
}
//batch mode: place directory locks on directories during both comparison AND synchronization
- LockHolder dummy(allowPwPrompt);
- std::for_each(cmpConfig.begin(), cmpConfig.end(),
- [&](const FolderPairCfg& fpCfg)
+
+ std::unique_ptr<LockHolder> dummy;
+ if (globSettings.createLockFile)
{
- dummy.addDir(fpCfg.leftDirectoryFmt, statusHandler);
- dummy.addDir(fpCfg.rightDirectoryFmt, statusHandler);
- });
+ dummy.reset(new LockHolder(allowPwPrompt));
+ std::for_each(cmpConfig.begin(), cmpConfig.end(),
+ [&](const FolderPairCfg& fpCfg)
+ {
+ dummy->addDir(fpCfg.leftDirectoryFmt, statusHandler);
+ dummy->addDir(fpCfg.rightDirectoryFmt, statusHandler);
+ });
+ }
//COMPARE DIRECTORIES
CompareProcess cmpProc(globSettings.fileTimeTolerance,
diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt
index c62c13e5..f300e42c 100644
--- a/BUILD/Changelog.txt
+++ b/BUILD/Changelog.txt
@@ -2,9 +2,34 @@
|FreeFileSync|
--------------
+Changelog v5.3
+--------------
+Show which processes lock a file during synchronization (Windows Vista and later)
+Use unbuffered copy to speed up copying large files (Windows Vista and later)
+Preserve NTFS sparse files
+Support referencing all logical volumes by name (including FreeOTFE virtual drives)
+Fixed lag showing "Searching for directory" on comparison
+New context menu filter option: exclude by short name
+Use clicked-on row rather than anchor when determining action for shift-selection
+Refresh grid after pressing "CTRL + A"
+Add base folder pairs to CSV export
+Show full path in tooltip if multiple folder pairs are used
+Show child dialogs on same monitor as parent dialog on multiple monitor systems
+Added statistics at beginning of batch log file
+Fixed batch mode final speed statistic and reset graph after binary comparison
+RealtimeSync: Automatically retry after 15 seconds if an error occurrs
+Show button images untrimmed (Linux)
+Fixed problems with auto-closing progress dialog (Linux)
+Fixed unresponsive progress dialog and systray icon (Linux)
+New option in GlobalSettings.xml: "LockDirectoriesDuringSync"
+Added Lithuanian translation
+Added Norwegian translation
+Updated translation files
+
+
Changelog v5.2
--------------
-Fixed runtime error "Error comparing strings! (LCMapString)" (Windows XP only)
+Fixed runtime error "Error comparing strings! (LCMapString)" (Windows 2000, XP only)
Changelog v5.1
diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm
index 5a59e94d..497b848e 100644
--- a/BUILD/FreeFileSync.chm
+++ b/BUILD/FreeFileSync.chm
Binary files differ
diff --git a/BUILD/Help/html/FreeFileSync.html b/BUILD/Help/html/FreeFileSync.html
index fe9457ad..446a5aa0 100644
--- a/BUILD/Help/html/FreeFileSync.html
+++ b/BUILD/Help/html/FreeFileSync.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="20120229;11541300">
+ <META NAME="CHANGED" CONTENT="20120408;21065300">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -99,6 +99,8 @@ Features</FONT></H3>
as a batch job</FONT></P>
<LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Multiple
folder pairs</FONT></P>
+ <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Preserve
+ NTFS sparse files</FONT></P>
<LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Support
very long path names &gt; 260 characters</FONT></P>
<LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Transactional
diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng
index fd5cbaf8..e40d8afc 100644
--- a/BUILD/Languages/chinese_simple.lng
+++ b/BUILD/Languages/chinese_simple.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>æµè§ˆç›®å½•</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>å–消请求: 正在等待当å‰æ“作完æˆ...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>实时åŒæ­¥ - 自动åŒæ­¥</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linuxé”™è¯¯ä»£ç  %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>解决符å·é“¾æŽ¥å‡ºé”™:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>无法解决 %x 的符å·è¿žæŽ¥.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -135,35 +138,41 @@
<pluralform>%x 字节</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>从åŒæ­¥æ•°æ®åº“中读å–时出错:</target>
+<source>Cannot read file %x.</source>
+<target>无法读å–文件 %x .</target>
-<source>Error writing to synchronization database:</source>
-<target>å‘åŒæ­¥æ•°æ®åº“中写入时出错:</target>
+<source>Cannot write file %x.</source>
+<target>无法写入文件 %x .</target>
-<source>Incompatible synchronization database format:</source>
-<target>ä¸å…¼å®¹çš„åŒæ­¥æ•°æ®åº“æ ¼å¼:</target>
+<source>Database file %x is incompatible.</source>
+<target>æ•°æ®åº“文件 %x ä¸å…¼å®¹.</target>
<source>Initial synchronization:</source>
<target>åˆå§‹åŒ–åŒæ­¥:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>FreeFileSyncæ•°æ®åº“文件其中一个ä¸å­˜åœ¨:</target>
+<source>Database file %x does not yet exist.</source>
+<target>æ•°æ®åº“文件 %x 还未存在.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>æ•°æ®åº“文件没ä¸å…±äº«ä¸€ä¸ªå…¬å…±çš„åŒæ­¥æ®µ</target>
+<source>Out of memory!</source>
+<target>内存ä¸è¶³!</target>
+
+<source>Database files do not share a common session.</source>
+<target>æ•°æ®åº“文件并未共享一个公共会è¯.</target>
<source>An exception occurred!</source>
<target>å‘生异常!</target>
-<source>Error reading file attributes:</source>
-<target>读å–文件属性出错:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>æ— æ³•è¯»å– %x 的文件属性.</target>
+
+<source>Cannot get process information.</source>
+<target>无法å–得进程信æ¯.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>由于目录已é”定而正在等待(%x)...</target>
-<source>Error setting directory lock:</source>
-<target>设置目录é”定时出错:</target>
+<source>Cannot set directory lock %x.</source>
+<target>无法设置目录é”定 %x .</target>
<source>
<pluralform>1 sec</pluralform>
@@ -173,8 +182,8 @@
<pluralform>%x 秒</pluralform>
</target>
-<source>Error reading file:</source>
-<target>读å–文件出错:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>当分æžæ–‡ä»¶ %x , è¡Œ %y, 列 %z 时出错.</target>
<source>Scanning:</source>
<target>扫æ中:</target>
@@ -190,38 +199,32 @@
<pluralform>[%x 线程]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>无效的 FreeFileSync é…置文件!</target>
+<source>/sec</source>
+<target>/秒</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>文件 %x 并未包å«åˆæ³•çš„é…ç½®.</target>
-<source>Error parsing configuration file:</source>
-<target>分æžé…置文件出错:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>é…置文件 %x åªæ˜¯éƒ¨åˆ†è½½å…¥.</target>
-<source>Configuration loaded partially only:</source>
-<target>åªéƒ¨åˆ†è½½å…¥é…置文件:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>无法访问å·å½±å¤åˆ¶æœåŠ¡.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>无法移动 %x 到回收站!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>请使用 FreeFileSync 64ä½ç‰ˆæœ¬æ¥åœ¨è¿™ä¸ªç³»ç»Ÿä¸Šåˆ›å»ºå·å½±å¤åˆ¶.</target>
<source>Cannot load file %x.</source>
<target>ä¸èƒ½è½½å…¥æ–‡ä»¶ %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>使用å·å½±å¤åˆ¶æœåŠ¡æ—¶å‡ºé”™!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>ä¸æ”¯æŒåœ¨WOW64上使用å·å½±å¤åˆ¶. 请使用 FreeFileSync 64ä½ç‰ˆæœ¬.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>ä¸èƒ½ç¡®å®šæ–‡ä»¶çš„å·å:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>路径 %x 并未包å«ä¸€ä¸ªå·å.</target>
<source>Volume name %x not part of file name %y!</source>
<target>å·å %x 并éžæ–‡ä»¶å %y 的一部分!</target>
-<source>/sec</source>
-<target>/秒</target>
-
-<source>File does not exist:</source>
-<target>文件ä¸å­˜åœ¨:</target>
+<source>Cannot find file %x.</source>
+<target>无法找到文件 %x .</target>
<source>Cannot read the following XML elements:</source>
<target>无法读å–如下XML元素:</target>
@@ -300,9 +303,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>实时åŒæ­¥é…ç½®</target>
-<source>File already exists. Overwrite?</source>
-<target>文件已ç»å­˜åœ¨.覆盖?</target>
-
<source>&Restore</source>
<target>æ¢å¤(&R)</target>
@@ -345,35 +345,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>FreeFileSync é…ç½®</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync 批处ç†ä½œä¸š</target>
-
-<source>Unable to create log file!</source>
-<target>无法创建日志!</target>
-
<source>Batch execution</source>
<target>批处ç†æ‰§è¡Œ</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>åŒæ­¥å·²æ”¾å¼ƒ!</target>
<source>Synchronization completed with errors!</source>
<target>åŒæ­¥å·²å®Œæˆä½†æœ‰é”™è¯¯.</target>
+<source>Nothing to synchronize!</source>
+<target>没有什么å¯åŒæ­¥!</target>
+
<source>Synchronization completed successfully!</source>
<target>åŒæ­¥æˆåŠŸå®Œæˆ!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>按"切æ¢"å¯æ‰“å¼€FreeFileSync图形用户界é¢æ¨¡å—.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>请按下"切æ¢"æ¥è§£å†³ FreeFileSync主对è¯æ¡†ä¸Šçš„问题.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>切æ¢è‡³FreeFileSync图形用户界é¢æ¨¡å—...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>正在切æ¢åˆ° FreeFileSync 主对è¯æ¡†...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>无法链接到 Sourceforge.net!</target>
@@ -531,9 +534,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>已找到的项目:</target>
-<source>Items remaining:</source>
-<target>剩余的项目:</target>
-
<source>Speed:</source>
<target>速度:</target>
@@ -561,9 +561,6 @@ The command line is executed each time:
<source>Right</source>
<target>å³ä¾§</target>
-<source>Sync setttings</source>
-<target>åŒæ­¥è®¾ç½®</target>
-
<source>Status feedback</source>
<target>状况å馈</target>
@@ -588,8 +585,8 @@ The command line is executed each time:
<source>&Load</source>
<target>加载(&L)</target>
-<source>&Cancel</source>
-<target>å–消(&C)</target>
+<source>Cancel</source>
+<target>å–消</target>
<source>Select variant:</source>
<target>选择å˜åŒ–çš„:</target>
@@ -639,8 +636,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>冲çª/文件ä¸èƒ½è¢«åˆ†ç±»</target>
-<source>&OK</source>
-<target>确定(&O)</target>
+<source>OK</source>
+<target>确定</target>
<source>Compare by...</source>
<target>比较选项...</target>
@@ -675,9 +672,6 @@ is the same
<source>Synchronizing...</source>
<target>åŒæ­¥ä¸­...</target>
-<source>Items processed:</source>
-<target>已处ç†çš„项目:</target>
-
<source>&Pause</source>
<target>æš‚åœ(&P)</target>
@@ -1017,9 +1011,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>文件清å•å·²ç»å¯¼å‡º!</target>
-<source>Error writing file:</source>
-<target>写入文件出错:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1061,21 +1052,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>已暂åœ</target>
+<source>Initializing...</source>
+<target>正在åˆå§‹åŒ–...</target>
+
<source>Aborted</source>
<target>å·²å–消</target>
<source>Completed</source>
<target>完æˆ</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>å–消请求: 正在等待当å‰æ“作完æˆ...</target>
+<source>Continue</source>
+<target>继续</target>
<source>Pause</source>
<target>æš‚åœ</target>
-<source>Continue</source>
-<target>继续</target>
-
<source>Cannot find %x</source>
<target>找ä¸åˆ° %x</target>
@@ -1209,68 +1200,65 @@ Exclude: \stuff\temp\*
<pluralform>%x 天</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>ä¸èƒ½åˆå§‹åŒ–目录监视:</target>
-
-<source>Error when monitoring directories.</source>
-<target>监视目录时出错.</target>
+<source>Cannot monitor directory %x.</source>
+<target>无法监视目录 %x.</target>
<source>Conversion error:</source>
<target>转æ¢é”™è¯¯:</target>
-<source>Error deleting file:</source>
-<target>删除文件出错:</target>
+<source>Cannot delete file %x.</source>
+<target>无法删除文件 %x.</target>
-<source>Error moving file:</source>
-<target>移动文件时出错:</target>
+<source>The file is locked by another process:</source>
+<target>此文件被å¦ä¸€è¿›ç¨‹é”定:</target>
-<source>Target file already existing!</source>
-<target>目标文件已ç»å­˜åœ¨!</target>
+<source>Cannot move file %x to %y.</source>
+<target>无法移动文件 %x 到 %y.</target>
-<source>Error moving directory:</source>
-<target>移动目录时出错:</target>
+<source>Cannot delete directory %x.</source>
+<target>无法删除目录 %x.</target>
-<source>Target directory already existing!</source>
-<target>目标目录已ç»å­˜åœ¨!</target>
+<source>Cannot write modification time of %x.</source>
+<target>无法写入 %x 的最åŽä¿®æ”¹æ—¶é—´.</target>
-<source>Error deleting directory:</source>
-<target>删除目录出错:</target>
+<source>Cannot find system function %x.</source>
+<target>无法找到系统功能 %x.</target>
-<source>Error changing modification time:</source>
-<target>改å˜ä¿®æ”¹æ—¶é—´æ—¶å‡ºé”™:</target>
+<source>Cannot read security context of %x.</source>
+<target>æ— æ³•è¯»å– %x 的安全上下文.</target>
-<source>Error loading library function:</source>
-<target>加载库函数出错:</target>
+<source>Cannot write security context of %x.</source>
+<target>无法写入 %x 的安全上下文.</target>
-<source>Error reading security context:</source>
-<target>读å–安全上下文时出错:</target>
+<source>Cannot read permissions of %x.</source>
+<target>æ— æ³•è¯»å– %x çš„æƒé™.</target>
-<source>Error writing security context:</source>
-<target>写入安全上下文时出错:</target>
+<source>Cannot write permissions of %x.</source>
+<target>无法写入 %x çš„æƒé™.</target>
-<source>Error copying file permissions:</source>
-<target>å¤åˆ¶æ–‡ä»¶æƒé™æ—¶å‡ºé”™:</target>
+<source>Cannot create directory %x.</source>
+<target>无法创建目录 %x.</target>
-<source>Error creating directory:</source>
-<target>创建目录出错:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>无法å¤åˆ¶ç¬¦å·è¿žæŽ¥ %x 到 %y.</target>
-<source>Error copying symbolic link:</source>
-<target>å¤åˆ¶ç¬¦å·é“¾æŽ¥æ—¶å‡ºé”™:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>无法写入 %x 的文件属性.</target>
-<source>Error copying file:</source>
-<target>å¤åˆ¶æ–‡ä»¶å‡ºé”™:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>无法å¤åˆ¶æ–‡ä»¶ %x 到 %y.</target>
-<source>Error opening file:</source>
-<target>打开文件出错:</target>
+<source>Cannot read directory %x.</source>
+<target>无法读å–目录 %x.</target>
-<source>Error traversing directory:</source>
-<target>é历目录出错:</target>
+<source>Endless loop.</source>
+<target>æ— é™å¾ªçŽ¯.</target>
-<source>Endless loop when traversing directory:</source>
-<target>é历目录时出现无é™å¾ªçŽ¯:</target>
+<source>Cannot set privilege %x.</source>
+<target>无法设置 %x 的特æƒ.</target>
-<source>Error setting privilege:</source>
-<target>设置æƒé™æ—¶å‡ºé”™:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>无法移动 %x 到回收站!</target>
<source>Both sides have changed since last synchronization!</source>
<target>在最åŽçš„åŒæ­¥ä¹‹åŽä¸¤è¾¹å‡å·²æ”¹å˜!</target>
@@ -1296,8 +1284,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>ä½ å¯ä»¥å¿½ç•¥è¿™ä¸ªé”™è¯¯è€Œè®¤ä¸ºç›®å½•æ˜¯ç©ºçš„.</target>
-<source>Directory does not exist:</source>
-<target>目录ä¸å­˜åœ¨:</target>
+<source>Cannot find directory %x.</source>
+<target>无法找到目录 %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>目录有ä¾èµ–性ï¼åœ¨è®¾ç«‹åŒæ­¥è§„则时请å°å¿ƒ:</target>
@@ -1305,20 +1293,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>正在准备åŒæ­¥...</target>
-<source>Out of memory!</source>
-<target>内存ä¸è¶³!</target>
+<source>Conflict detected:</source>
+<target>检测到冲çª:</target>
<source>File %x has an invalid date!</source>
<target>文件 %x 的日期éžæ³•!</target>
-<source>Conflict detected:</source>
-<target>检测到冲çª:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>文件 %x 日期相åŒä½†å¤§å°ä¸åŒ!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>符å·è¿žæŽ¥ %x 有相åŒçš„日期但目标ä¸åŒ!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>符å·è¿žæŽ¥ %x 有相åŒçš„日期但目标ä¸åŒ.</target>
<source>Comparing content of files %x</source>
<target>正在比较文件 %x 的内容</target>
@@ -1401,12 +1386,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>正在创建文件 %x</target>
-<source>Creating folder %x</source>
-<target>正创建文件夹 %x</target>
-
<source>Creating symbolic link %x</source>
<target>正在创建符å·è¿žæŽ¥ %x</target>
+<source>Creating folder %x</source>
+<target>正创建文件夹 %x</target>
+
<source>Overwriting file %x</source>
<target>正在覆盖文件 %x</target>
@@ -1425,8 +1410,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>用于ä¿å­˜æ–‡ä»¶åŽ†å²ç‰ˆæœ¬çš„目录没有æä¾›!</target>
-<source>Source directory does not exist anymore:</source>
-<target>æºç›®å½•å·²ç»ä¸å­˜åœ¨:</target>
+<source>Source directory %x not found.</source>
+<target>æ¥æºç›®å½• %x 无法找到.</target>
<source>Unresolved conflicts existing!</source>
<target>存在ä¸å¯è§£å†³çš„冲çª!</target>
@@ -1461,12 +1446,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>正在生æˆæ•°æ®åº“...</target>
-<source>Nothing to synchronize!</source>
-<target>没有什么å¯åŒæ­¥!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>无法å¤åˆ¶å·²é”定文件 %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>æ•°æ®æ ¡éªŒé”™è¯¯:æºæ–‡ä»¶å’Œç›®æ ‡æ–‡ä»¶å†…容ä¸åŒ!</target>
diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng
index c222463d..69414e19 100644
--- a/BUILD/Languages/chinese_traditional.lng
+++ b/BUILD/Languages/chinese_traditional.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>ç€è¦½ç›®éŒ„</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>中止請求:正在等待目å‰æ“作完æˆ...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>å³æ™‚åŒæ­¥ - 自動åŒæ­¥</target>
+<source>Error</source>
+<target>錯誤</target>
+
<source>Select alternate comparison settings</source>
<target>é¸æ“‡æ›¿ä»£çš„比å°è¨­å®š</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>關於</target>
-<source>Error</source>
-<target>錯誤</target>
-
<source>Warning</source>
<target>警告</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux錯誤代碼 %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>解æžéŒ¯èª¤çš„符號連çµï¼š</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>無法解æžç¬¦è™Ÿé€£çµ %X。</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -135,35 +138,41 @@
<pluralform>%x ä½å…ƒçµ„</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>讀å–åŒæ­¥è³‡æ–™åº«éŒ¯èª¤ï¼š</target>
+<source>Cannot read file %x.</source>
+<target>無法讀å–檔案 %X。</target>
-<source>Error writing to synchronization database:</source>
-<target>寫入åŒæ­¥è³‡æ–™åº«éŒ¯èª¤ï¼š</target>
+<source>Cannot write file %x.</source>
+<target>無法寫入檔案 %X。</target>
-<source>Incompatible synchronization database format:</source>
-<target>åŒæ­¥è³‡æ–™åº«æ ¼å¼ä¸ç›¸å®¹ï¼š</target>
+<source>Database file %x is incompatible.</source>
+<target>資料庫檔案 %x 是ä¸ç›¸å®¹çš„。</target>
<source>Initial synchronization:</source>
<target>åˆå§‹åŒ–åŒæ­¥ï¼š</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>其中一個FreeFileSync資料庫檔案ä¸å­˜åœ¨ï¼š</target>
+<source>Database file %x does not yet exist.</source>
+<target>資料庫檔案 %x 並ä¸å­˜åœ¨ã€‚</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>資料庫檔案ä¸è¦å…±äº«ä¸€å€‹å…±åŒçš„åŒæ­¥é€£ç·šï¼š</target>
+<source>Out of memory!</source>
+<target>記憶體ä¸è¶³ï¼</target>
+
+<source>Database files do not share a common session.</source>
+<target>資料庫檔案ä¸æœƒå…±äº«ä¸€å€‹å…±åŒçš„連線。</target>
<source>An exception occurred!</source>
<target>發生異常ï¼</target>
-<source>Error reading file attributes:</source>
-<target>讀å–檔案屬性錯誤:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>ç„¡æ³•è®€å– %x 的檔案屬性。</target>
+
+<source>Cannot get process information.</source>
+<target>無法得到進程資訊。</target>
<source>Waiting while directory is locked (%x)...</source>
<target>等待åŒæ™‚目錄被鎖定(%x)...</target>
-<source>Error setting directory lock:</source>
-<target>設定目錄鎖錯誤:</target>
+<source>Cannot set directory lock %x.</source>
+<target>無法設定目錄鎖 %x。</target>
<source>
<pluralform>1 sec</pluralform>
@@ -173,8 +182,8 @@
<pluralform>%x 秒</pluralform>
</target>
-<source>Error reading file:</source>
-<target>讀å–檔案錯誤:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>解æžæª”案 %xã€è¡Œ %yã€åˆ— %z 時出ç¾éŒ¯èª¤ã€‚</target>
<source>Scanning:</source>
<target>正在掃瞄:</target>
@@ -190,38 +199,32 @@
<pluralform>[%x 個執行緒]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>無效的FreeFileSyncé…置檔案ï¼</target>
+<source>/sec</source>
+<target>/秒</target>
-<source>Error parsing configuration file:</source>
-<target>分æžé…置檔案錯誤:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>檔案 %x ä¸åŒ…å«ä¸€å€‹æœ‰æ•ˆçš„é…置。</target>
-<source>Configuration loaded partially only:</source>
-<target>åªè¼‰å…¥éƒ¨åˆ†é…置:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>åªè¼‰å…¥è¨­å®šæª” %x 的一部份。</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>無法將 %x 移動到資æºå›žæ”¶ç­’ï¼</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>無法讀å–å·å½±è¤‡è£½æœå‹™ã€‚</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>請在此系統上使用FreeFileSync 64ä½å…ƒç‰ˆæœ¬ä¾†æ–°å»ºå·å½±å‰¯æœ¬ã€‚</target>
<source>Cannot load file %x.</source>
<target>無法載入檔案 %x。</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>讀å–å·å½±è¤‡è£½æœå‹™æ™‚錯誤ï¼</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>ä¸æ”¯æ´WOW64製作å·å½±å‰¯æœ¬ã€‚請使用FreeFileSync 64ä½å…ƒç‰ˆæœ¬ã€‚</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>無法判斷檔案å·å:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>路徑 %x ä¸åŒ…å«å·å。</target>
<source>Volume name %x not part of file name %y!</source>
<target>å·å %x 並éžæª”å %y 的一部份ï¼</target>
-<source>/sec</source>
-<target>/秒</target>
-
-<source>File does not exist:</source>
-<target>檔案ä¸å­˜åœ¨ï¼š</target>
+<source>Cannot find file %x.</source>
+<target>找ä¸åˆ°æª”案 %x。</target>
<source>Cannot read the following XML elements:</source>
<target>無法讀å–下列XML元素:</target>
@@ -294,15 +297,18 @@ The command line is executed each time:
<source>Start</source>
<target>開始</target>
+<source>&Retry</source>
+<target>é‡è©¦(&R)</target>
+
+<source>Cancel</source>
+<target>å–消</target>
+
<source>(Build: %x)</source>
<target>(建立:%x)</target>
<source>RealtimeSync configuration</source>
<target>å³æ™‚åŒæ­¥é…ç½®</target>
-<source>File already exists. Overwrite?</source>
-<target>檔案已存在,è¦è¦†è“‹å—Žï¼Ÿ</target>
-
<source>&Restore</source>
<target>還原(&R)</target>
@@ -345,35 +351,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>FreeFileSyncé…ç½®</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync批次處ç†ä½œæ¥­</target>
-
-<source>Unable to create log file!</source>
-<target>無法新建日誌檔ï¼</target>
-
<source>Batch execution</source>
<target>批次處ç†åŸ·è¡Œ</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>åŒæ­¥å·²ä¸­æ­¢ï¼</target>
<source>Synchronization completed with errors!</source>
<target>åŒæ­¥å®Œæˆä½†æœ‰éŒ¯èª¤ï¼</target>
+<source>Nothing to synchronize!</source>
+<target>沒有什麼æ±è¥¿å¯åŒæ­¥ï¼</target>
+
<source>Synchronization completed successfully!</source>
<target>å·²æˆåŠŸçš„完æˆåŒæ­¥ï¼</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>按下 "切æ›" é–‹å•ŸFreeFileSync圖形介é¢æ“作方å¼ã€‚</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>在FreeFileSync主å°è©±æ¡†ï¼ŒæŒ‰ä¸‹"切æ›"來解決å•é¡Œã€‚</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>切æ›FreeFileSync圖形介é¢æ“作方å¼...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>切æ›åˆ°FreeFileSync主å°è©±æ¡†...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>無法連接到sourceforge.netï¼</target>
@@ -531,9 +540,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>尋找項目:</target>
-<source>Items remaining:</source>
-<target>剩餘項目:</target>
-
<source>Speed:</source>
<target>速度:</target>
@@ -561,9 +567,6 @@ The command line is executed each time:
<source>Right</source>
<target>å³é‚Š</target>
-<source>Sync setttings</source>
-<target>åŒæ­¥è¨­å®š</target>
-
<source>Status feedback</source>
<target>狀態回報</target>
@@ -588,9 +591,6 @@ The command line is executed each time:
<source>&Load</source>
<target>載入(&L)</target>
-<source>&Cancel</source>
-<target>å–消(&C)</target>
-
<source>Select variant:</source>
<target>é¸æ“‡è®Šæ•¸ï¼š</target>
@@ -639,8 +639,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>è¡çª/檔案無法分類</target>
-<source>&OK</source>
-<target>確定(&O)</target>
+<source>OK</source>
+<target>確定</target>
<source>Compare by...</source>
<target>比å°é¸é …...</target>
@@ -666,9 +666,6 @@ is the same
<source>Synchronizing...</source>
<target>正在åŒæ­¥...</target>
-<source>Items processed:</source>
-<target>已處ç†é …目:</target>
-
<source>&Pause</source>
<target>æš«åœ(&P)</target>
@@ -708,9 +705,6 @@ is the same
<source>&Ignore</source>
<target>忽略(&I)</target>
-<source>&Retry</source>
-<target>é‡è©¦(&R)</target>
-
<source>Do not show this dialog again</source>
<target>ä¸è¦å†é¡¯ç¤ºæ­¤å°è©±æ¡†</target>
@@ -1008,9 +1002,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>檔案清單已匯出ï¼</target>
-<source>Error writing file:</source>
-<target>寫入檔案錯誤:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1052,21 +1043,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>已暫åœ</target>
+<source>Initializing...</source>
+<target>正在åˆå§‹åŒ–...</target>
+
<source>Aborted</source>
<target>已中止</target>
<source>Completed</source>
<target>已完æˆ</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>中止請求:正在等待目å‰æ“作完æˆ...</target>
+<source>Continue</source>
+<target>繼續</target>
<source>Pause</source>
<target>æš«åœ</target>
-<source>Continue</source>
-<target>繼續</target>
-
<source>Cannot find %x</source>
<target>找ä¸åˆ° %x</target>
@@ -1200,68 +1191,65 @@ Exclude: \stuff\temp\*
<pluralform>%x 天</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>無法åˆå§‹åŒ–目錄監測:</target>
-
-<source>Error when monitoring directories.</source>
-<target>監測目錄錯誤。</target>
+<source>Cannot monitor directory %x.</source>
+<target>無法監測目錄 %x。</target>
<source>Conversion error:</source>
<target>轉æ›éŒ¯èª¤ï¼š</target>
-<source>Error deleting file:</source>
-<target>刪除檔案錯誤:</target>
+<source>Cannot delete file %x.</source>
+<target>無法刪除目錄 %x。</target>
-<source>Error moving file:</source>
-<target>移動檔案錯誤:</target>
+<source>The file is locked by another process:</source>
+<target>檔案被å¦ä¸€å€‹é€²ç¨‹éŽ–定:</target>
-<source>Target file already existing!</source>
-<target>目標檔案已存在ï¼</target>
+<source>Cannot move file %x to %y.</source>
+<target>無法移動檔案 %x 到 %y。</target>
-<source>Error moving directory:</source>
-<target>移動目錄錯誤:</target>
+<source>Cannot delete directory %x.</source>
+<target>無法刪除目錄 %x。</target>
-<source>Target directory already existing!</source>
-<target>目標目錄已存在ï¼</target>
+<source>Cannot write modification time of %x.</source>
+<target>無法寫入 %x 的修改時間。</target>
-<source>Error deleting directory:</source>
-<target>刪除目錄錯誤:</target>
+<source>Cannot find system function %x.</source>
+<target>找ä¸åˆ°ç³»çµ±å‡½æ•¸ %x。</target>
-<source>Error changing modification time:</source>
-<target>變更修改時間錯誤:</target>
+<source>Cannot read security context of %x.</source>
+<target>ç„¡æ³•è®€å– %x 的安全上下文。</target>
-<source>Error loading library function:</source>
-<target>載入函數庫錯誤:</target>
+<source>Cannot write security context of %x.</source>
+<target>無法寫入 %x 的安全上下文。</target>
-<source>Error reading security context:</source>
-<target>讀å–安全性內容錯誤:</target>
+<source>Cannot read permissions of %x.</source>
+<target>ç„¡æ³•è®€å– %x 的權é™ã€‚</target>
-<source>Error writing security context:</source>
-<target>寫入安全性內容錯誤:</target>
+<source>Cannot write permissions of %x.</source>
+<target>無法寫入 %x 的權é™ã€‚</target>
-<source>Error copying file permissions:</source>
-<target>複製檔案權é™éŒ¯èª¤ï¼š</target>
+<source>Cannot create directory %x.</source>
+<target>無法新建目錄 %x。</target>
-<source>Error creating directory:</source>
-<target>新建目錄錯誤:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>ç„¡æ³•è¤‡è£½ç¬¦è™Ÿé€£çµ %x 到 %y。</target>
-<source>Error copying symbolic link:</source>
-<target>複製符號連çµéŒ¯èª¤ï¼š</target>
+<source>Cannot write file attributes of %x.</source>
+<target>無法寫入 %x 的檔案屬性。</target>
-<source>Error copying file:</source>
-<target>複製檔案錯誤:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>無法複製檔案 %x 到 %y。</target>
-<source>Error opening file:</source>
-<target>開啟檔案錯誤:</target>
+<source>Cannot read directory %x.</source>
+<target>無法讀å–目錄 %x。</target>
-<source>Error traversing directory:</source>
-<target>é歷目錄錯誤:</target>
+<source>Endless loop.</source>
+<target>ç„¡é™è¿´åœˆã€‚</target>
-<source>Endless loop when traversing directory:</source>
-<target>當é歷目錄時無é™å¾ªç’°ï¼š</target>
+<source>Cannot set privilege %x.</source>
+<target>ç„¡æ³•è¨­å®šæ¬Šé™ %x。</target>
-<source>Error setting privilege:</source>
-<target>設定權é™éŒ¯èª¤ï¼š</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>無法將 %x 移動到資æºå›žæ”¶ç­’ï¼</target>
<source>Both sides have changed since last synchronization!</source>
<target>自上次åŒæ­¥å¾Œï¼Œå…©é‚Šå‡å·²æ›´æ”¹éŽï¼</target>
@@ -1287,8 +1275,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>您å¯ä»¥å¿½ç•¥æ­¤éŒ¯èª¤ï¼Œè€ƒæ…®è©²ç›®éŒ„為空。</target>
-<source>Directory does not exist:</source>
-<target>目錄ä¸å­˜åœ¨ï¼š</target>
+<source>Cannot find directory %x.</source>
+<target>找ä¸åˆ°ç›®éŒ„ %x。</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>目錄有ä¾é æ€§ï¼è«‹å°å¿ƒè¨­å®šåŒæ­¥è¦å‰‡ï¼š</target>
@@ -1296,20 +1284,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>正在準備åŒæ­¥...</target>
-<source>Out of memory!</source>
-<target>記憶體ä¸è¶³ï¼</target>
+<source>Conflict detected:</source>
+<target>檢測到è¡çªï¼š</target>
<source>File %x has an invalid date!</source>
<target>檔案 %x 的日期無效ï¼</target>
-<source>Conflict detected:</source>
-<target>檢測到è¡çªï¼š</target>
-
<source>Files %x have the same date but a different size!</source>
<target>檔案 %x 日期相åŒä½†å¤§å°ä¸åŒï¼</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>ç¬¦è™Ÿé€£çµ %x 有相åŒæ—¥æœŸä½†æ˜¯ä¸åŒç›®æ¨™ï¼</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>%x 的符號連çµå…·æœ‰ç›¸åŒçš„日期,但ä¸åŒçš„目標。</target>
<source>Comparing content of files %x</source>
<target>正在比å°æª”案内容 %x</target>
@@ -1392,12 +1377,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>正在新建檔案 %x</target>
-<source>Creating folder %x</source>
-<target>正在新建資料夾 %x</target>
-
<source>Creating symbolic link %x</source>
<target>æ­£åœ¨æ–°å»ºç¬¦è™Ÿé€£çµ %x</target>
+<source>Creating folder %x</source>
+<target>正在新建資料夾 %x</target>
+
<source>Overwriting file %x</source>
<target>正在覆蓋檔案 %x</target>
@@ -1416,8 +1401,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>版本控制檔的目錄ä¸æä¾›ï¼</target>
-<source>Source directory does not exist anymore:</source>
-<target>來æºç›®éŒ„ä¸å­˜åœ¨ï¼š</target>
+<source>Source directory %x not found.</source>
+<target>來æºç›®éŒ„ %x 找ä¸åˆ°ã€‚</target>
<source>Unresolved conflicts existing!</source>
<target>存在未解決的è¡çªï¼</target>
@@ -1452,12 +1437,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>正在產生資料庫...</target>
-<source>Nothing to synchronize!</source>
-<target>沒有什麼æ±è¥¿å¯åŒæ­¥ï¼</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>無法複製被鎖定的檔案 %Xï¼</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>資料驗證錯誤:來æºå’Œç›®æ¨™æª”案內容ä¸åŒï¼</target>
diff --git a/BUILD/Languages/croatian.lng b/BUILD/Languages/croatian.lng
index 708eda95..ff56257e 100644
--- a/BUILD/Languages/croatian.lng
+++ b/BUILD/Languages/croatian.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Odaberi direktorij</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Prekid zahtjevan: Äekam da se trenutna akcija zavrÅ¡i...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatska Sinkronizacija</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux greška %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Pogreška pri otvaranju poveznice simbola:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Ne mogu rijeÅ¡iti simboliÄnu poveznicu</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -137,35 +140,41 @@
<pluralform>%x Bajtova</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>GreÅ¡ka pri Äitanju iz sinkronizacijske baze:</target>
+<source>Cannot read file %x.</source>
+<target>Ne mogu Äitati datoteku</target>
-<source>Error writing to synchronization database:</source>
-<target>Greška pri pisanju u sinkronizacijsku bazu:</target>
+<source>Cannot write file %x.</source>
+<target>Ne mogu zapisati datoteku</target>
-<source>Incompatible synchronization database format:</source>
-<target>Nekompatibilan format sinkronizacijske podatkovne baze:</target>
+<source>Database file %x is incompatible.</source>
+<target>Datoteka baze %x je nekompatibilna</target>
<source>Initial synchronization:</source>
<target>PoÄetna sinkronizacija:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Jedna od FreeFileSync datoteka podatkovne baze još ne postoji:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Datoteka baze %x još ne postoji</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Datoteke podatkovne baze ne dijele zajedniÄke sinkronizacijske sesije:</target>
+<source>Out of memory!</source>
+<target>Nedostatak memorije</target>
+
+<source>Database files do not share a common session.</source>
+<target>Datoteke baze ne dijele zajedniÄki protokol</target>
<source>An exception occurred!</source>
<target>Dogodilo se izuzeće!</target>
-<source>Error reading file attributes:</source>
-<target>GreÅ¡ka pri Äitanju atributa datoteke:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Ne mogu proÄitati osobine od %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Ne mogu dobit iniformacije o procesu</target>
<source>Waiting while directory is locked (%x)...</source>
<target>ÄŒekam dok se direktorij zakljuÄava (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>GreÅ¡ka pri postavljanju zakljuÄenja direktorija:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Ne mogu zakljuÄati direktorij %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x sek</pluralform>
</target>
-<source>Error reading file:</source>
-<target>GreÅ¡ka pri Äitanju datoteke:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Greška u analizi datoteke %x, red %y, stupac %z.</target>
<source>Scanning:</source>
<target>Pretražujem:</target>
@@ -196,38 +205,32 @@
<pluralform>% Stavki</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Nevaljana FreeFileSync konfiguracijska datoteka!</target>
+<source>/sec</source>
+<target>/sek</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Datoteka %x ne sadrži valjanu konfiguraciju</target>
-<source>Error parsing configuration file:</source>
-<target>GreÅ¡ka pri raÅ¡Älanjivanju datoteke postavki:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Datoteka postavki %x uÄitana samo djelomiÄno</target>
-<source>Configuration loaded partially only:</source>
-<target>Konfiguracija uÄitala samo djelomiÄno:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Ne mogu pristupiti Volume Shadow Copy Servisu</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Nije moguće prebaciti u Koš za smeće</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Molimo koristite FreeFileSync 64-bitnu verziju za izradu shadow kopija na ovom sustavu</target>
<source>Cannot load file %x.</source>
<target>Ne mogu uÄitati datoteku %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Greška pri pristupu servisu particijskog kopiranja!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Stvaranje sjeniÄnih kopija na WOW63 nije podržano. Molimo koristite 64-bitnu FreeFileSync inaÄnicu.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Nemože se ustanoviti naziv datoteke</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Putanja %x ne sadrži naziv particije</target>
<source>Volume name %x not part of file name %y!</source>
<target>Naziv particije %x dio naziva datoteke %y!</target>
-<source>/sec</source>
-<target>/sek</target>
-
-<source>File does not exist:</source>
-<target>Datoteka ne postoji:</target>
+<source>Cannot find file %x.</source>
+<target>Ne mogu pronaći datoteku %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Ne mogu Äitati slijedeće XML elemente</target>
@@ -306,9 +309,6 @@ Naredba će biti izvršena kada:
<source>RealtimeSync configuration</source>
<target>RealtimeSync postavke</target>
-<source>File already exists. Overwrite?</source>
-<target>Datoteka već postoji. Prepisati?</target>
-
<source>&Restore</source>
<target>&Vrati</target>
@@ -351,35 +351,38 @@ Naredba će biti izvršena kada:
<source>FreeFileSync configuration</source>
<target>FreeFileSync postavke</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Slijedni zadatak</target>
-
-<source>Unable to create log file!</source>
-<target>Nemogu napraviti zapisnik!</target>
-
<source>Batch execution</source>
<target>Slijedno izvršavanje</target>
-<source>Stop</source>
-<target>Zaustavi</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>Synchronization aborted!</source>
<target>Sinkronizacija prekinuta!</target>
<source>Synchronization completed with errors!</source>
<target>Sinkronizacija završena s greškama!</target>
+<source>Nothing to synchronize!</source>
+<target>Ništa za sinkronizirati!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sinkronizacija uspješno završena!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Pretisnite "Zamjena", da otvorite FreeFileSync GUI naÄin.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Preisni "Zamjeni" za riješavanje problema u FreeFileSync glavnom dijaloškom okviru</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Prelazim na FreeFileSync GUI naÄin...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Prebacujem u FreeFileSync glavni dijaloški okvir</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Ne mogu se povezati na sourceforge.net!</target>
@@ -537,9 +540,6 @@ Naredba će biti izvršena kada:
<source>Items found:</source>
<target>Pronađene stavke:</target>
-<source>Items remaining:</source>
-<target>Preostale stavke:</target>
-
<source>Speed:</source>
<target>Brzina:</target>
@@ -591,8 +591,8 @@ Naredba će biti izvršena kada:
<source>&Load</source>
<target>&Uvezi</target>
-<source>&Cancel</source>
-<target>&Odustani</target>
+<source>Cancel</source>
+<target>Odustani</target>
<source>Select variant:</source>
<target>Izaberite varijantu:</target>
@@ -642,8 +642,8 @@ Naredba će biti izvršena kada:
<source>Conflict/file cannot be categorized</source>
<target>Konflikt/datoteka ne more biti kategorizirana</target>
-<source>&OK</source>
-<target>&U redu</target>
+<source>OK</source>
+<target>U redu</target>
<source>Compare by...</source>
<target>Usporedi prema...</target>
@@ -678,9 +678,6 @@ jednak
<source>Synchronizing...</source>
<target>Sinkroniziram...</target>
-<source>Items processed:</source>
-<target>Obrađeni elementi:</target>
-
<source>&Pause</source>
<target>&Pauziraj</target>
@@ -1020,9 +1017,6 @@ IskljuÄi: \stuff\temp\*
<source>File list exported!</source>
<target>DatoteÄna lista izvezena!</target>
-<source>Error writing file:</source>
-<target>Napaka pri pisanju datoteke:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1072,21 +1066,21 @@ IskljuÄi: \stuff\temp\*
<source>Paused</source>
<target>Pauzirano</target>
+<source>Initializing...</source>
+<target>UÄitavam</target>
+
<source>Aborted</source>
<target>Prekinuto</target>
<source>Completed</source>
<target>Završeno</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Prekid zahtjevan: Äekam da se trenutna akcija zavrÅ¡i...</target>
+<source>Continue</source>
+<target>Nastavi</target>
<source>Pause</source>
<target>Pauziraj</target>
-<source>Continue</source>
-<target>Nastavi</target>
-
<source>Cannot find %x</source>
<target>Nemogu pronać %x</target>
@@ -1230,65 +1224,65 @@ IskljuÄi: \stuff\temp\*
<pluralform>%x dana</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Ne mogu zapoÄeti nadziranje direktorija:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Greška pri nadziranju direktorija.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Ne mogu posmatrati direktorij %x.</target>
<source>Conversion error:</source>
<target>Greška pri pretvorbi:</target>
-<source>Error deleting file:</source>
-<target>Greška pri brisanju datoteke:</target>
+<source>Cannot delete file %x.</source>
+<target>Ne mogu izbrisati datoteku %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Datoteka je blokirana drugim procesom:</target>
-<source>Error moving file:</source>
-<target>Greška pri premještanju datoteke:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Ne mogu premjestiti datoteku %x u %y.</target>
-<source>Target file already existing!</source>
-<target>Ciljna datoteka već postoji!</target>
+<source>Cannot delete directory %x.</source>
+<target>Ne mogu izbrisati mapu %x.</target>
-<source>Error moving directory:</source>
-<target>Greška pri premještanju direktorija:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Ne mogu zapisati vrijeme izmjene %x.</target>
-<source>Target directory already existing!</source>
-<target>Ciljni direktorij već postoji!</target>
+<source>Cannot find system function %x.</source>
+<target>Ne mogu pronaći sistemsku funkciju %x.</target>
-<source>Error deleting directory:</source>
-<target>Greška pri brisanju direktorija:</target>
+<source>Cannot read security context of %x.</source>
+<target>Ne mogu Äitati zaÅ¡tićeni sadržaj %x.</target>
-<source>Error changing modification time:</source>
-<target>Greška pri promjeni vremena izmjene:</target>
+<source>Cannot write security context of %x.</source>
+<target>Ne mogu zapisati zaštićeni sadržaj %x.</target>
-<source>Error loading library function:</source>
-<target>Greška pri zadavanju funkcije iz knjižnice:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Ne mogu Äitati dopuÅ¡tenja od %x.</target>
-<source>Error reading security context:</source>
-<target>GreÅ¡ka pri Äitanju zaÅ¡tićenog sadržaja:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Ne mogu zapisati dopuštenja za %x.</target>
-<source>Error writing security context:</source>
-<target>Greška pri pisanju zaštićenog sadržaja:</target>
+<source>Cannot create directory %x.</source>
+<target>Ne mogu izraditi mapu %x.</target>
-<source>Error copying file permissions:</source>
-<target>GreÅ¡ka pri kopiranju datoteÄnih dopuÅ¡tenja:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Ne mogu kopirati simboliÄnu poveznicu %x na %y.</target>
-<source>Error creating directory:</source>
-<target>Greška pri izradi direktorija:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ne mogu zapisati svojstva od %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Greška pri kopiranju poveznice simbola:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Ne mogu kopirati datoteku %x na %y.</target>
-<source>Error copying file:</source>
-<target>Greška pri kopiranju datoteke:</target>
+<source>Cannot read directory %x.</source>
+<target>Ne mogu Äitati mapu %x.</target>
-<source>Error traversing directory:</source>
-<target>Greška pri prelasku direktorija:</target>
+<source>Endless loop.</source>
+<target>Beskrajna petlja</target>
-<source>Endless loop when traversing directory:</source>
-<target>BeskonaÄna petlja pri prelasku direktorija:</target>
+<source>Cannot set privilege %x.</source>
+<target>Ne mogu postaviti prava za %x.</target>
-<source>Error setting privilege:</source>
-<target>Greška pri postavljanju dopuštenja:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Nije moguće prebaciti u Koš za smeće</target>
<source>Both sides have changed since last synchronization!</source>
<target>Obje su strane promjenjene od posljednje sinkronizacije!</target>
@@ -1314,8 +1308,8 @@ IskljuÄi: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Možete ignorirati ovu grešku uzimajući datoteku kao praznu .</target>
-<source>Directory does not exist:</source>
-<target>Direktorij ne postoji:</target>
+<source>Cannot find directory %x.</source>
+<target>Ne mogu pronaći mapu %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Direktoriji su u ovisnosti! Budite oprezni pri postavljanju sinkronizacijskih pravila:</target>
@@ -1323,20 +1317,17 @@ IskljuÄi: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Pripremam sinkronizaciju</target>
-<source>Out of memory!</source>
-<target>Nedostatak memorije</target>
+<source>Conflict detected:</source>
+<target>Sukob pronađen:</target>
<source>File %x has an invalid date!</source>
<target>Datoteka %x ima nevaljan datum!</target>
-<source>Conflict detected:</source>
-<target>Sukob pronađen:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Datoteke %x imaju isti datum ali drugaÄiju veliÄinu!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>SimboliÄne poveznice %x imaju isti datum ali drugaÄiji cilj!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>SimboliÄne poveznice %x imaju isti datum ali drugaÄiji cilj</target>
<source>Comparing content of files %x</source>
<target>Uspoređujem sadržaj datoteka %x</target>
@@ -1419,12 +1410,12 @@ IskljuÄi: \stuff\temp\*
<source>Creating file %x</source>
<target>Izrađujem datoteku %x</target>
-<source>Creating folder %x</source>
-<target>Izrađujem mapu %x</target>
-
<source>Creating symbolic link %x</source>
<target>IzraÄ‘ujem simboliÄnu poveznicu %x</target>
+<source>Creating folder %x</source>
+<target>Izrađujem mapu %x</target>
+
<source>Overwriting file %x</source>
<target>Prepisujem datoteku %x</target>
@@ -1443,8 +1434,8 @@ IskljuÄi: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Mapa za ovakvu datoteku nije isporuÄena</target>
-<source>Source directory does not exist anymore:</source>
-<target>Izvorni direktorij više ne postoji:</target>
+<source>Source directory %x not found.</source>
+<target>Izvorna mapa %x nije pronađena</target>
<source>Unresolved conflicts existing!</source>
<target>Nerješivi sukob postoji!</target>
@@ -1479,12 +1470,6 @@ IskljuÄi: \stuff\temp\*
<source>Generating database...</source>
<target>Izrađujem bazu podataka...</target>
-<source>Nothing to synchronize!</source>
-<target>Ništa za sinkronizirati!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Nemoguće kopirati blokiranu datoteku %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>GreÅ¡ka pri provjeravanju podataka: Izvorna i ciljna datoteka imaju razliÄit sadržaj!</target>
diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng
index cd0aa8f0..3230b30b 100644
--- a/BUILD/Languages/czech.lng
+++ b/BUILD/Languages/czech.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Procházet adresář</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Požadavek na pÅ™eruÅ¡ení: ÄŒekání na ukonÄení aktuální operace...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatická synchronizace</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Chybový kód Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Nelze najít odkaz zástupce:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Nelze najít odkaz zástupce %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -137,35 +140,41 @@
<pluralform>%x B</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Nelze Äíst ze synchronizaÄní databáze:</target>
+<source>Cannot read file %x.</source>
+<target>Nelze Äíst soubor %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Nelze zapsat do synchronizaÄní databáze:</target>
+<source>Cannot write file %x.</source>
+<target>Nelze zapsat soubor %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Chybný formát synchronizaÄní databáze:</target>
+<source>Database file %x is incompatible.</source>
+<target>Chybný formát databáze %x.</target>
<source>Initial synchronization:</source>
<target>Prvotní synchronizace:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Některý z databázových souborů FreeFileSync neexistuje:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Databázový soubor %x neexistuje.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Databázové soubory nejsou navzájem komplementární</target>
+<source>Out of memory!</source>
+<target>Nedostatek pracovní paměti!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Databázové soubory nejsou navzájem komplementární.</target>
<source>An exception occurred!</source>
<target>Vyskytla se chyba!</target>
-<source>Error reading file attributes:</source>
-<target>Nelze Äíst atributy souboru:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Nelze Äíst atributy souboru %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Nelze získat informace procesu.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>ÄŒekání na uzamÄení adresáře (%x)</target>
-<source>Error setting directory lock:</source>
-<target>Nelze nastavit zámek adresáře:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Nelze nastavit zámek adresáře %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x sekund</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Nelze Äíst soubor:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Chyba zpracování souboru %x: na řádku %y ve sloupci %z</target>
<source>Scanning:</source>
<target>Zpracováváno:</target>
@@ -196,38 +205,32 @@
<pluralform>[%x procesů]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Chybný konfiguraÄní soubor FreeFileSync!</target>
+<source>/sec</source>
+<target>/s</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Soubor %x neobsahuje platnou konfiguraci.</target>
-<source>Error parsing configuration file:</source>
-<target>Nelze zpracovat konfiguraÄní soubor:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Konfigurace ze souboru %x byla naÄtena jen ÄásteÄnÄ›.</target>
-<source>Configuration loaded partially only:</source>
-<target>Konfigurace byla naÄtena jen ÄásteÄnÄ›:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Nepodařil se přístup ke službě Volume Shadow Copy Service.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Není možné přesunout %x do Koše!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Prosím použijte FreeFileSync 64-bitovou verzi pro použití služby Volume Shadow Copy.</target>
<source>Cannot load file %x.</source>
<target>Nelze naÄíst soubor %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Nepodařil se přístup ke službě Volume Shadow Copy Service!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Vytváření stínových kopií na WOW64 není podporováno. Prosím použijte 64 bitovou verzi FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Nelze zjistit jméno jednotky souboru:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>>Nelze zjistit jméno jednotky souboru %x.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Disk %x není souÄástí jména souboru %y!</target>
-<source>/sec</source>
-<target>/s</target>
-
-<source>File does not exist:</source>
-<target>Soubor neexistuje:</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>
@@ -306,9 +309,6 @@ Příkazová řádka je spuštěna pokaždé když:
<source>RealtimeSync configuration</source>
<target>Konfigurace RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Soubor již existuje. Přepsat?</target>
-
<source>&Restore</source>
<target>&Obnovit</target>
@@ -351,35 +351,38 @@ Příkazová řádka je spuštěna pokaždé když:
<source>FreeFileSync configuration</source>
<target>Konfigurace FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Dávkové zpracování</target>
-
-<source>Unable to create log file!</source>
-<target>Není možné vytvořit záznamový soubor!</target>
-
<source>Batch execution</source>
<target>Spuštění dávky</target>
-<source>Stop</source>
-<target>Stop</target>
+<source>Items processed:</source>
+<target>Zpracováno položek:</target>
+
+<source>Items remaining:</source>
+<target>Zbývá položek:</target>
<source>Total time:</source>
<target>Celkový Äas:</target>
+<source>Stop</source>
+<target>Stop</target>
+
<source>Synchronization aborted!</source>
<target>Synchronizace zrušena!</target>
<source>Synchronization completed with errors!</source>
<target>Synchronizace dokonÄena s chybami.</target>
+<source>Nothing to synchronize!</source>
+<target>Není co synchronizovat!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronizace dokonÄena úspěšnÄ›!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>TalÄítkem "PÅ™epnout" otevÅ™ete okno FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Použijte tlaÄítko "PÅ™epnout" k vyÅ™eÅ¡ení problému pomocí hlavního okna FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Otevírání okna FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Přepínání do hlavního okna FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Není možné se připojit k sourceforge.net!</target>
@@ -537,9 +540,6 @@ Příkazová řádka je spuštěna pokaždé když:
<source>Items found:</source>
<target>Nalezeno položek:</target>
-<source>Items remaining:</source>
-<target>Zbývá položek:</target>
-
<source>Speed:</source>
<target>Rychlost:</target>
@@ -591,8 +591,8 @@ Příkazová řádka je spuštěna pokaždé když:
<source>&Load</source>
<target>&NaÄíst</target>
-<source>&Cancel</source>
-<target>&Zrušit</target>
+<source>Cancel</source>
+<target>Zrušit</target>
<source>Select variant:</source>
<target>Vyberte variantu:</target>
@@ -642,8 +642,8 @@ Příkazová řádka je spuštěna pokaždé když:
<source>Conflict/file cannot be categorized</source>
<target>Konflikty/soubory které nelze zařadit</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Porovnat ...</target>
@@ -678,9 +678,6 @@ je stejný
<source>Synchronizing...</source>
<target>Synchronizuji...</target>
-<source>Items processed:</source>
-<target>Zpracováno položek:</target>
-
<source>&Pause</source>
<target>&Pauza</target>
@@ -1020,9 +1017,6 @@ Vynechat: \někde\něco\*
<source>File list exported!</source>
<target>Seznam souborů exportován!</target>
-<source>Error writing file:</source>
-<target>Nelze zapsat souboru:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1072,21 +1066,21 @@ Vynechat: \někde\něco\*
<source>Paused</source>
<target>Pauza</target>
+<source>Initializing...</source>
+<target>Inicializace...</target>
+
<source>Aborted</source>
<target>Přerušeno</target>
<source>Completed</source>
<target>Hotovo</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Požadavek na pÅ™eruÅ¡ení: ÄŒekání na ukonÄení aktuální operace...</target>
+<source>Continue</source>
+<target>PokraÄovat</target>
<source>Pause</source>
<target>Pauza</target>
-<source>Continue</source>
-<target>PokraÄovat</target>
-
<source>Cannot find %x</source>
<target>Nelze najít %x</target>
@@ -1230,65 +1224,65 @@ Vynechat: \někde\něco\*
<pluralform>%x dnů</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Nelze nastavit monitorování adresáře:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Nelze pokraÄovat ve sledování adresářů.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Nelze nastavit monitorování adresáře %x.</target>
<source>Conversion error:</source>
<target>Chyba konverze:</target>
-<source>Error deleting file:</source>
-<target>Nelze smazat soubor:</target>
+<source>Cannot delete file %x.</source>
+<target>Nelze smazat soubor %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Soubor je uzamÄen jiným procesem:</target>
-<source>Error moving file:</source>
-<target>Nelze přesunout soubor:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Nelze přesunout soubor %x do %y.</target>
-<source>Target file already existing!</source>
-<target>Cílový soubor již existuje!</target>
+<source>Cannot delete directory %x.</source>
+<target>Nelze smazat adresář %x.</target>
-<source>Error moving directory:</source>
-<target>Nelze přesunout adresář:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Nelze nastavit atribut Äasu zmÄ›ny pro %x.</target>
-<source>Target directory already existing!</source>
-<target>Cílový adresář již existuje!</target>
+<source>Cannot find system function %x.</source>
+<target>Nelze najít systémovou funkci %x.</target>
-<source>Error deleting directory:</source>
-<target>Nelze smazat adresář:</target>
+<source>Cannot read security context of %x.</source>
+<target>Nelze Äíst přístupová práva pro %x.</target>
-<source>Error changing modification time:</source>
-<target>Nelze nastavit atribut Äasu zmÄ›ny:</target>
+<source>Cannot write security context of %x.</source>
+<target>Nelze zapsat přístupová práva pro %x.</target>
-<source>Error loading library function:</source>
-<target>NepodaÅ™ilo se naÄíst funkci z knihovny:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Nelze Äíst oprávnÄ›ní pro %x.</target>
-<source>Error reading security context:</source>
-<target>Nelze Äíst přístupová práva:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Nelze zapsat oprávnění pro %x.</target>
-<source>Error writing security context:</source>
-<target>Nelze zapsat přístupová práva:</target>
+<source>Cannot create directory %x.</source>
+<target>Nelze vytvořit adresář %x.</target>
-<source>Error copying file permissions:</source>
-<target>Nelze kopírovat oprávnění souboru:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Nelze kopítovat zástupce %x do %y.</target>
-<source>Error creating directory:</source>
-<target>Nelze vytvořit adresář:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nelze zapsat atributy souboru %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Nelze kopírovat zástupce:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Nelze kopírovat soubor %x do %y.</target>
-<source>Error copying file:</source>
-<target>Nelze kopírovat souboru:</target>
+<source>Cannot read directory %x.</source>
+<target>Nelze Äíst adresář %x.</target>
-<source>Error traversing directory:</source>
-<target>Nelze procházet adresář:</target>
+<source>Endless loop.</source>
+<target>NekoneÄná smyÄka.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Zacyklení při procházení adresáře:</target>
+<source>Cannot set privilege %x.</source>
+<target>Nelze nastavit práva pro %x.</target>
-<source>Error setting privilege:</source>
-<target>Nelze nastavit práva:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Není možné přesunout %x do Koše!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Došlo ke změně obou stran od poslední synchronizace!</target>
@@ -1314,8 +1308,8 @@ Vynechat: \někde\něco\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Tuto chybu můžete pÅ™eskoÄit a považovat neexistující adresář jako prázdný.</target>
-<source>Directory does not exist:</source>
-<target>Adresář neexistuje:</target>
+<source>Cannot find directory %x.</source>
+<target>Nelze najít adresář %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Adresáře jsou závislé! BuÄte opatrní s definicí synchronizaÄních pravidel:</target>
@@ -1323,20 +1317,17 @@ Vynechat: \někde\něco\*
<source>Preparing synchronization...</source>
<target>Příprava synchronizace...</target>
-<source>Out of memory!</source>
-<target>Nedostatek pracovní paměti!</target>
+<source>Conflict detected:</source>
+<target>Zaznamenán konflikt:</target>
<source>File %x has an invalid date!</source>
<target>Soubor %x má chybné datum!</target>
-<source>Conflict detected:</source>
-<target>Zaznamenán konflikt:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Soubory %x mají stejné datum a Äas ale rozdílnou velikost!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Symbolický odkaz %x má stejné datum ale jiný cíl!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Symbolický odkaz %x má stejné datum ale jiný cíl.</target>
<source>Comparing content of files %x</source>
<target>Porovnávání obsahu souborů %x</target>
@@ -1419,12 +1410,12 @@ Vynechat: \někde\něco\*
<source>Creating file %x</source>
<target>Vytváření souboru %x</target>
-<source>Creating folder %x</source>
-<target>Vytváření adresáře %x</target>
-
<source>Creating symbolic link %x</source>
<target>Vytváření symbolického odkazu %x</target>
+<source>Creating folder %x</source>
+<target>Vytváření adresáře %x</target>
+
<source>Overwriting file %x</source>
<target>Přepisování souboru %x</target>
@@ -1443,8 +1434,8 @@ Vynechat: \někde\něco\*
<source>Directory for file versioning was not supplied!</source>
<target>Nebyl zadán adresář pro verzování souborů!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Zdrojový adresář již neexistuje:</target>
+<source>Source directory %x not found.</source>
+<target>Zdrojový adresář %x nelze najít.</target>
<source>Unresolved conflicts existing!</source>
<target>Nevyřešené konflikty!</target>
@@ -1479,12 +1470,6 @@ Vynechat: \někde\něco\*
<source>Generating database...</source>
<target>Vytváření databáze...</target>
-<source>Nothing to synchronize!</source>
-<target>Není co synchronizovat!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Nelze kopírovat zamÄený souboru %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Nezdařila se verifikace dat: Zdrojový a cílový soubor mají rozdílný obsah!</target>
diff --git a/BUILD/Languages/danish.lng b/BUILD/Languages/danish.lng
index 08634a4f..d524b0bd 100644
--- a/BUILD/Languages/danish.lng
+++ b/BUILD/Languages/danish.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Gennemse Bibliotek</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Afbrydelse: Venter på nuværende opgave afsluttes...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSynk - Automatisk Synkronisering</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Fejl kode %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Fejl i at finde link:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Kan ikke følge linket %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Fejl i læsning fra synkroniserings databasen:</target>
+<source>Cannot read file %x.</source>
+<target>Kan ikke læse filen %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Fejl i skrivning til synkroniserings databasen:</target>
+<source>Cannot write file %x.</source>
+<target>Kan ikke skrive filen %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Ukompatibelt synkroniserings database format:</target>
+<source>Database file %x is incompatible.</source>
+<target>Database filen %x er ikke kompatibel.</target>
<source>Initial synchronization:</source>
<target>Indledende synkronisering:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>En af FreeFileSync database filerne findes ikke endnu:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Database filen %x findes ikke.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Database filer deler ikke en fælles synkroniserings session</target>
+<source>Out of memory!</source>
+<target>Ude af hukommelse!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Database filen kan ikke deles.</target>
<source>An exception occurred!</source>
<target>En undtagelse er opstået!</target>
-<source>Error reading file attributes:</source>
-<target>Fejl i læsning af atributter:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Kan ikke læse fil attributterne på %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Kan ikke lave informationer over processen.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Venter mens biblioteket er låst (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Fejl i at låse bibliotek:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Kan ikke låse biblioteket %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sek</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Fejl i læsning af fil:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Fejl i videregivelse af filen %x, række %y, kolonne %z.</target>
<source>Scanning:</source>
<target>Skanner:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Tråde]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Ugyldig FreeFileSync config fil!</target>
+<source>/sec</source>
+<target>/sek</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>%x indeholder ikke en gyldig konfiguration.</target>
-<source>Error parsing configuration file:</source>
-<target>Fejl i at lave konfigurations filen:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Konfigurationsfilen %x er kun delvist hentet.</target>
-<source>Configuration loaded partially only:</source>
-<target>Konfiguration kun delvist hentet:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Kan ikke få adgang til Drev Kopi Servicen.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ude af stand til at flytte %x til skraldespanden!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Brug venligst FreeFileSync 64-bit version for at lave en drev kopi på dette system.</target>
<source>Cannot load file %x.</source>
<target>Kan ikke læse filen %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Fejl i adgang til Enhedens Kopi Service</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>At lave spejl kopier af WOW64 er ikke understøttet. Brug venligst FreeFileSync 64-bit version.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Kan ikke bestemme drev navn for filen:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Stien %x indeholder ikke et drev navn.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Drev navn %x ikke en del af filnavn %y!</target>
-<source>/sec</source>
-<target>/sek</target>
-
-<source>File does not exist:</source>
-<target>Filen findes ikke:</target>
+<source>Cannot find file %x.</source>
+<target>Kan ikke finde filen %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Kan ikke læse følgende XML emner:</target>
@@ -303,9 +306,6 @@ Kommando linjen bliver afviklet hver gang:
<source>RealtimeSync configuration</source>
<target>RealtimeSynk konfiguration</target>
-<source>File already exists. Overwrite?</source>
-<target>Filen findes. Overskriv?</target>
-
<source>&Restore</source>
<target>&Gendan</target>
@@ -348,35 +348,38 @@ Kommando linjen bliver afviklet hver gang:
<source>FreeFileSync configuration</source>
<target>FreeFileSync konfiguration</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Batch Job</target>
-
-<source>Unable to create log file!</source>
-<target>Kan ikke oprette logfil!</target>
-
<source>Batch execution</source>
<target>Batch afvikling</target>
-<source>Stop</source>
-<target>Stop</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>Synchronization aborted!</source>
<target>Synkronisering afbrudt!</target>
<source>Synchronization completed with errors!</source>
<target>Synkronisering afsluttet med fejl!</target>
+<source>Nothing to synchronize!</source>
+<target>Intet at synkronisere!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synkronisering afsluttet uden fejl!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Tryk "Skift" for at åbne FreeFileSync i GUI mode.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Tryk "Skift" for at løse problemer i hoved vinduet.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Skifter til FreeFileSync GUI mode...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Skift til hoved vinduet...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Kan ikke forbinde til sourceforge.net!</target>
@@ -534,9 +537,6 @@ Kommando linjen bliver afviklet hver gang:
<source>Items found:</source>
<target>Enheder fundet:</target>
-<source>Items remaining:</source>
-<target>Enheder tilbage:</target>
-
<source>Speed:</source>
<target>Hastighed:</target>
@@ -564,9 +564,6 @@ Kommando linjen bliver afviklet hver gang:
<source>Right</source>
<target>Højre</target>
-<source>Sync setttings</source>
-<target>Synkroniser indstillinger</target>
-
<source>Status feedback</source>
<target>Status feedback</target>
@@ -591,8 +588,8 @@ Kommando linjen bliver afviklet hver gang:
<source>&Load</source>
<target>&Hent</target>
-<source>&Cancel</source>
-<target>&Anuller</target>
+<source>Cancel</source>
+<target>Anuller</target>
<source>Select variant:</source>
<target>Vælg variant:</target>
@@ -642,8 +639,8 @@ Kommando linjen bliver afviklet hver gang:
<source>Conflict/file cannot be categorized</source>
<target>Konflikt/filen kan ikke kategoriseres</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Sammenlign ved...</target>
@@ -678,9 +675,6 @@ er det samme
<source>Synchronizing...</source>
<target>Synkroniserer...</target>
-<source>Items processed:</source>
-<target>Enheder behandlet:</target>
-
<source>&Pause</source>
<target>&Pause</target>
@@ -1020,9 +1014,6 @@ Udeluk: \ting\temp\*
<source>File list exported!</source>
<target>Fil listen er eksporteret!</target>
-<source>Error writing file:</source>
-<target>Fejl i at skrive fil:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1068,21 +1059,21 @@ Udeluk: \ting\temp\*
<source>Paused</source>
<target>Pauset</target>
+<source>Initializing...</source>
+<target>Initialiserer...</target>
+
<source>Aborted</source>
<target>Afbrudt</target>
<source>Completed</source>
<target>Fuldført</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Afbrydelse: Venter på nuværende opgave afsluttes...</target>
+<source>Continue</source>
+<target>Fortsæt</target>
<source>Pause</source>
<target>Pause</target>
-<source>Continue</source>
-<target>Fortsæt</target>
-
<source>Cannot find %x</source>
<target>Kan ikke finde %x</target>
@@ -1221,68 +1212,65 @@ Udeluk: \ting\temp\*
<pluralform>%x dage</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Kunne ikke initialiserer biblioteks overvågningen:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Fejl i overvågning af biblioteker.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Kan ikke overvåge biblioteket %x.</target>
<source>Conversion error:</source>
<target>Konverterings fejl:</target>
-<source>Error deleting file:</source>
-<target>Fejl i sletning af fil:</target>
+<source>Cannot delete file %x.</source>
+<target>Kan ikke slette filen %x.</target>
-<source>Error moving file:</source>
-<target>Fejl i flytning af fil:</target>
+<source>The file is locked by another process:</source>
+<target>Filen er låst af en anden process:</target>
-<source>Target file already existing!</source>
-<target>Filen findes i forvejen!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Kan ikke flytte filen %x til %y.</target>
-<source>Error moving directory:</source>
-<target>Fejl i flytning af bibliotek:</target>
+<source>Cannot delete directory %x.</source>
+<target>Kan ikke slette biblioteket %x.</target>
-<source>Target directory already existing!</source>
-<target>Bibliotek findes i forvejen!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Kan ikke opdatere ændringstiden på %x.</target>
-<source>Error deleting directory:</source>
-<target>Fejl i sletning af bibliotek:</target>
+<source>Cannot find system function %x.</source>
+<target>Kan ikke finde systemfunktionen %x.</target>
-<source>Error changing modification time:</source>
-<target>Fejl i ændring af modificerings tiden:</target>
+<source>Cannot read security context of %x.</source>
+<target>Kan ikke læse sikkerhedsindstillingerne på %x.</target>
-<source>Error loading library function:</source>
-<target>Fejl i biblioteks funktionen:</target>
+<source>Cannot write security context of %x.</source>
+<target>Kan ikke skrive sikkerhedsindstillingerne på %x.</target>
-<source>Error reading security context:</source>
-<target>Fejl i læsning af sikkerhedstilladelser:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Kan ikke læse tilladelserne på %x.</target>
-<source>Error writing security context:</source>
-<target>Fejl i skrivning af sikkerhedstilladelser:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Kan ikke skrive tilladelserne til %x.</target>
-<source>Error copying file permissions:</source>
-<target>Fejl i kopiering af filtilladelser:</target>
+<source>Cannot create directory %x.</source>
+<target>Kan ikke oprette biblioteket %x.</target>
-<source>Error creating directory:</source>
-<target>Fejl i oprettelse af bibliotek:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Kan ikke kopiere linket %x til %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Fejl i kopiering af link:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan ikke skrive fil attributter til %x.</target>
-<source>Error copying file:</source>
-<target>Fejl i kopiering af fil:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Kan ikke kopiere filen %x til %y.</target>
-<source>Error opening file:</source>
-<target>Fejl i åbning af fil:</target>
+<source>Cannot read directory %x.</source>
+<target>Kan ikke læse biblioteket %x.</target>
-<source>Error traversing directory:</source>
-<target>Fejl i gennemgang af bibliotek:</target>
+<source>Endless loop.</source>
+<target>Uendelig løkke.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Uendelig løkke ved gennemgang af bibliotek:</target>
+<source>Cannot set privilege %x.</source>
+<target>Kan ikke sætte privilegier til %x.</target>
-<source>Error setting privilege:</source>
-<target>Fejl i at sætte privilegier:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ude af stand til at flytte %x til skraldespanden!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Begge sider er ændret siden sidste synkronisering!</target>
@@ -1308,8 +1296,8 @@ Udeluk: \ting\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Du kan ignorer denne fejl, og opfatte biblioteket som tomt.</target>
-<source>Directory does not exist:</source>
-<target>Biblioteket findes ikke:</target>
+<source>Cannot find directory %x.</source>
+<target>Kan ikke finde biblioteket %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Biblioteker er afhængige! Vær forsigtig når du laver synkroniserings reglerne:</target>
@@ -1317,20 +1305,17 @@ Udeluk: \ting\temp\*
<source>Preparing synchronization...</source>
<target>Forbereder synkronisering...</target>
-<source>Out of memory!</source>
-<target>Ude af hukommelse!</target>
+<source>Conflict detected:</source>
+<target>Konflik fundet:</target>
<source>File %x has an invalid date!</source>
<target>Filen %x har en ugyldig dato!</target>
-<source>Conflict detected:</source>
-<target>Konflik fundet:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Filerne %x har den samme dato men forskellig størrelse!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Links %x har den samme dato men forskellige destinationerl!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Linksene %x har samme dato men forskellige mål.</target>
<source>Comparing content of files %x</source>
<target>Sammenligner indhold af filer %x</target>
@@ -1413,12 +1398,12 @@ Udeluk: \ting\temp\*
<source>Creating file %x</source>
<target>Opretter filen %x</target>
-<source>Creating folder %x</source>
-<target>Opretter mappe %x</target>
-
<source>Creating symbolic link %x</source>
<target>Opretter linket %x</target>
+<source>Creating folder %x</source>
+<target>Opretter mappe %x</target>
+
<source>Overwriting file %x</source>
<target>Overskriver filen %x</target>
@@ -1437,8 +1422,8 @@ Udeluk: \ting\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Fil versions biblioteket blev ikke angivet!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Kilde biblioteket findes ikke mere:</target>
+<source>Source directory %x not found.</source>
+<target>Kildebiblioteket %x blev ikke fundet.</target>
<source>Unresolved conflicts existing!</source>
<target>Er er uløste konflikter!</target>
@@ -1473,12 +1458,6 @@ Udeluk: \ting\temp\*
<source>Generating database...</source>
<target>Opretter database...</target>
-<source>Nothing to synchronize!</source>
-<target>Intet at synkronisere!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Ude af stand til at kopiere låst fil %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Data godkendelses fejl: Kilde og destinations fil har forskelligt indhold!</target>
diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng
index 9a2ac4f7..0e7c3cb9 100644
--- a/BUILD/Languages/dutch.lng
+++ b/BUILD/Languages/dutch.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>Verken map</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Bezig met afbreken: Wacht op beëindiging huidige bewerking...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Geautomatiseerde Synchronisatie</target>
+<source>Error</source>
+<target>Fout</target>
+
<source>Select alternate comparison settings</source>
<target>Selecteer alternatieve vergelijkings instellingen</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>Informatie</target>
-<source>Error</source>
-<target>Fout</target>
-
<source>Warning</source>
<target>Waarschuwing</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Fout Code %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Fout tijdens opzoeken van snelkoppeling:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Kan snelkoppeling %x niet vinden.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Fout tijdens uitlezen van synchronisatie-database:</target>
+<source>Cannot read file %x.</source>
+<target>Kan bestand %x niet vinden.</target>
-<source>Error writing to synchronization database:</source>
-<target>Fout tijdens schrijven naar synchronisatie-database:</target>
+<source>Cannot write file %x.</source>
+<target>Kan bestand %x niet schrijven.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Opmaak van synchronisatie-database komt niet overeen:</target>
+<source>Database file %x is incompatible.</source>
+<target>Database bestand %x is niet compatibel.</target>
<source>Initial synchronization:</source>
<target>Initiële synchronisatie:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Eén van de FreeFileSync database bestanden bestaat nog niet:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Database bestand %x bestaat nog niet.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Database bestanden delen geen gezamelijke synchronisatie sessie:</target>
+<source>Out of memory!</source>
+<target>Onvoldoende geheugen!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Database bestanden delen geen gezamelijke sessie.</target>
<source>An exception occurred!</source>
<target>Er heeft een uitzondering plaatsgevonden!</target>
-<source>Error reading file attributes:</source>
-<target>Fout tijdens lezen van bestandsattributen</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Kan bestandskenmerken van %x niet uitlezen.</target>
+
+<source>Cannot get process information.</source>
+<target>Kan geen procesinformatie verkrijgen.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Wacht totdat map is vergrendeld (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Fout tijdens mapvergrendeling:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Kan directory %x niet sluiten.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sec</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Fout tijdens lezen van bestand:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Fout bij het parsen van bestand %x, rij %y, kolom %z.</target>
<source>Scanning:</source>
<target>Doorzoekt:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Foutief FreeFileSync configuratiebestand!</target>
+<source>/sec</source>
+<target>/sec</target>
-<source>Error parsing configuration file:</source>
-<target>Fout tijdens verwerking configuratiebestand:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>Bestand %x bevat geen valide configuratie.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configuratie alleen gedeeltelijk geladen:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Configuratie bestand %x alleen deels geladen.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Niet mogelijk om %x naar de Prullenbak te verplaatsen!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Kan de Volume Schaduwkopie Service niet benaderen.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Gebruik alstublieft de FreeFileSync 64-bit versie om schaduwkopieën te maken op dit systeem.</target>
<source>Cannot load file %x.</source>
<target>Kan bestand %x niet laden.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Fout bij toegang tot Volume Schaduwkopie Service!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Het aanmaken van schaduwkopieën op WOW64 wordt niet ondersteund. Gebruik alstublieft de 64-bit versie van FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Kan volumenaam niet bepalen voor bestand:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Het pad %x bevat geen schijfnaam.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Schijfnaam %x maakt geen deel uit van bestandsnaam %y!</target>
-<source>/sec</source>
-<target>/sec</target>
-
-<source>File does not exist:</source>
-<target>Bestand bestaat niet:</target>
+<source>Cannot find file %x.</source>
+<target>Kan bestand %x niet vinden.</target>
<source>Cannot read the following XML elements:</source>
<target>Kan de volgende XML elementen niet lezen:</target>
@@ -297,15 +300,18 @@ De opdrachtregel wordt telkens uitgevoerd indien:
<source>Start</source>
<target>Start</target>
+<source>&Retry</source>
+<target>&Opnieuw proberen</target>
+
+<source>Cancel</source>
+<target>Annuleren</target>
+
<source>(Build: %x)</source>
<target>(Build: %x)</target>
<source>RealtimeSync configuration</source>
<target>RealtimeSync configuratie</target>
-<source>File already exists. Overwrite?</source>
-<target>Bestand bestaat al. Overschrijven?</target>
-
<source>&Restore</source>
<target>&Herstellen</target>
@@ -348,35 +354,38 @@ De opdrachtregel wordt telkens uitgevoerd indien:
<source>FreeFileSync configuration</source>
<target>FreeFileSync configuratie</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Taaklijst</target>
-
-<source>Unable to create log file!</source>
-<target>Niet in staat om een logbestand aan te maken!</target>
-
<source>Batch execution</source>
<target>Taak uitvoeren</target>
-<source>Stop</source>
-<target>Stop</target>
+<source>Items processed:</source>
+<target>Onderdelen verwerkt:</target>
+
+<source>Items remaining:</source>
+<target>Onderdelen te gaan:</target>
<source>Total time:</source>
<target>Totale tijd:</target>
+<source>Stop</source>
+<target>Stop</target>
+
<source>Synchronization aborted!</source>
<target>Synchronisatie afgebroken!</target>
<source>Synchronization completed with errors!</source>
<target>Synchronisatie is met fouten afgerond!</target>
+<source>Nothing to synchronize!</source>
+<target>Niks om te synchroniseren!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronisatie succesvol afgerond!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Toets "Switch" om FreeFileSync GUI mode te openen.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Druk op "Omschakelen" om problemen op te lossen in het hoofdscherm van FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Schakelt over naar FreeFileSync GUI mode...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Bezig met omschakelen naar het FreeFileSync hoofdscherm.</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Niet in staat verbinding te maken met sourceforge.net!</target>
@@ -534,9 +543,6 @@ De opdrachtregel wordt telkens uitgevoerd indien:
<source>Items found:</source>
<target>Onderdelen gevonden:</target>
-<source>Items remaining:</source>
-<target>Onderdelen te gaan:</target>
-
<source>Speed:</source>
<target>Snelheid:</target>
@@ -588,9 +594,6 @@ De opdrachtregel wordt telkens uitgevoerd indien:
<source>&Load</source>
<target>&Laden</target>
-<source>&Cancel</source>
-<target>&Annuleren</target>
-
<source>Select variant:</source>
<target>Selecteer een variant:</target>
@@ -639,8 +642,8 @@ De opdrachtregel wordt telkens uitgevoerd indien:
<source>Conflict/file cannot be categorized</source>
<target>Conflict/Bestand kan niet worden gecategoriseerd</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Vergelijk met...</target>
@@ -675,9 +678,6 @@ overeenkomt
<source>Synchronizing...</source>
<target>Synchroniseert...</target>
-<source>Items processed:</source>
-<target>Onderdelen verwerkt:</target>
-
<source>&Pause</source>
<target>&Pauze</target>
@@ -717,14 +717,11 @@ overeenkomt
<source>&Ignore</source>
<target>&Negeren</target>
-<source>&Retry</source>
-<target>&Opnieuw proberen</target>
-
<source>Do not show this dialog again</source>
<target>Toon deze melding niet meer</target>
<source>&Switch</source>
-<target>&Verander</target>
+<target>&Omschakelen</target>
<source>&Yes</source>
<target>&Ja</target>
@@ -1017,9 +1014,6 @@ Uitsluiten: \stuff\temp\*
<source>File list exported!</source>
<target>Bestandslijst geëxporteerd!</target>
-<source>Error writing file:</source>
-<target>Fout tijdens schrijven van bestand:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Uitsluiten: \stuff\temp\*
<source>Paused</source>
<target>Gepauzeerd</target>
+<source>Initializing...</source>
+<target>Initialiseren...</target>
+
<source>Aborted</source>
<target>Afgebroken</target>
<source>Completed</source>
<target>Volbracht</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Bezig met afbreken: Wacht op beëindiging huidige bewerking...</target>
+<source>Continue</source>
+<target>Doorgaan</target>
<source>Pause</source>
<target>Pauze</target>
-<source>Continue</source>
-<target>Doorgaan</target>
-
<source>Cannot find %x</source>
<target>Kan %x niet vinden</target>
@@ -1218,65 +1212,65 @@ Uitsluiten: \stuff\temp\*
<pluralform>%x dagen</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Initaliseren van map-observatie niet mogelijk:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Fout tijdens observeren van mappen.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Kan locatie %x niet controleren.</target>
<source>Conversion error:</source>
<target>Converteer fout:</target>
-<source>Error deleting file:</source>
-<target>Fout tijdens verwijderen van bestand:</target>
+<source>Cannot delete file %x.</source>
+<target>Kan bestand %x niet verwijderen.</target>
-<source>Error moving file:</source>
-<target>Fout tijdens verplaatsen van bestand:</target>
+<source>The file is locked by another process:</source>
+<target>Het bestand is op afgesloten door een ander proces:</target>
-<source>Target file already existing!</source>
-<target>Doelbestand bestaat al!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Kan bestand %x niet verplaatsen naar %y.</target>
-<source>Error moving directory:</source>
-<target>Fout tijdens verplaatsen van map:</target>
+<source>Cannot delete directory %x.</source>
+<target>Kan bestand %x niet verwijderen.</target>
-<source>Target directory already existing!</source>
-<target>Doelmap bestaat al!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Kan wijzigings tijd van %x niet toevoegen.</target>
-<source>Error deleting directory:</source>
-<target>Fout tijdens het verwijderen van map:</target>
+<source>Cannot find system function %x.</source>
+<target>Kan systeemfunctie %x niet vinden.</target>
-<source>Error changing modification time:</source>
-<target>Fout tijdens aanpassing van de wijzigingstijd:</target>
+<source>Cannot read security context of %x.</source>
+<target>Kan de beveiligingscontext van %x niet lezen.</target>
-<source>Error loading library function:</source>
-<target>Fout tijdens laden van bibliotheek functie:</target>
+<source>Cannot write security context of %x.</source>
+<target>Kan de beveiligingscontext van %x niet schrijven.</target>
-<source>Error reading security context:</source>
-<target>Fout tijdens lezen van beveiligingscontext:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Kan de bevoegdheden van %x niet lezen.</target>
-<source>Error writing security context:</source>
-<target>Fout tijdens schrijven van beveiligingscontext:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Kan de bevoegdheden van %x niet schrijven.</target>
-<source>Error copying file permissions:</source>
-<target>Fout tijdens kopiëren van bestandspermissies:</target>
+<source>Cannot create directory %x.</source>
+<target>Kan map %x niet aanmaken.</target>
-<source>Error creating directory:</source>
-<target>Fout tijdens het aanmaken van map:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Kan snelkoppeling %x niet kopiëren naar %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Fout tijdens kopiëren van snelkoppeling:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan bestandskenmerken van %x niet schrijven.</target>
-<source>Error copying file:</source>
-<target>Fout tijdens kopiëren van bestand:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Kan bestand %x niet kopiëren naar %y.</target>
-<source>Error traversing directory:</source>
-<target>Fout tijdens doorzoeken van map:</target>
+<source>Cannot read directory %x.</source>
+<target>Kan map %x niet lezen.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Oneindige lus bij het doorlopen van map:</target>
+<source>Endless loop.</source>
+<target>Oneindige loop.</target>
-<source>Error setting privilege:</source>
-<target>Fout tijdens instellen van privileges:</target>
+<source>Cannot set privilege %x.</source>
+<target>Kan privilege %x niet instellen.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Niet mogelijk om %x naar de Prullenbak te verplaatsen!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Beide zijdes zijn veranderd sinds de laatste synchronisatie!</target>
@@ -1302,8 +1296,8 @@ Uitsluiten: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Je kan deze error negeren als de map leeg is.</target>
-<source>Directory does not exist:</source>
-<target>Map bestaat niet:</target>
+<source>Cannot find directory %x.</source>
+<target>Kan map %x niet vinden.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Mappen zijn afhankelijk van elkaar! Wees voorzichtig met het maken van synchronisatieregels:</target>
@@ -1311,20 +1305,17 @@ Uitsluiten: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Synchronisatie voorbereiden</target>
-<source>Out of memory!</source>
-<target>Onvoldoende geheugen!</target>
+<source>Conflict detected:</source>
+<target>Conflict gedetecteerd:</target>
<source>File %x has an invalid date!</source>
<target>Bestand %x heeft een ongeldige datum!</target>
-<source>Conflict detected:</source>
-<target>Conflict gedetecteerd:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Bestanden %x hebben dezelfde datums maar een afwijkende grootte!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Snelkoppeling %x heeft dezelfde datum maar een ander doel!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Snelkoppelingen %x hebben dezelfde datum maar een verschillend doel.</target>
<source>Comparing content of files %x</source>
<target>De inhoud van %x bestanden wordt vergeleken</target>
@@ -1407,12 +1398,12 @@ Uitsluiten: \stuff\temp\*
<source>Creating file %x</source>
<target>Bestand %x wordt aangemaakt</target>
-<source>Creating folder %x</source>
-<target>Map %x wordt aangemaakt</target>
-
<source>Creating symbolic link %x</source>
<target>Snelkoppeling %x wordt aangemaakt</target>
+<source>Creating folder %x</source>
+<target>Map %x wordt aangemaakt</target>
+
<source>Overwriting file %x</source>
<target>Bezig met overschrijven van bestand %x</target>
@@ -1431,8 +1422,8 @@ Uitsluiten: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Map voor bestands versiebeheer is niet ingegeven!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Bronmap bestaat niet meer:</target>
+<source>Source directory %x not found.</source>
+<target>Bronmap %x niet gevonden.</target>
<source>Unresolved conflicts existing!</source>
<target>Er bestaan onopgeloste conflicten!</target>
@@ -1467,12 +1458,6 @@ Uitsluiten: \stuff\temp\*
<source>Generating database...</source>
<target>Genereren van database...</target>
-<source>Nothing to synchronize!</source>
-<target>Niks om te synchroniseren!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Niet in staat om vergrendeld bestand %x te synchroniseren!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Dataverificatie-fout: Bron en doelbestand hebben verschillende inhoud!</target>
diff --git a/BUILD/Languages/english_uk.lng b/BUILD/Languages/english_uk.lng
index 000b07d0..abed9c59 100644
--- a/BUILD/Languages/english_uk.lng
+++ b/BUILD/Languages/english_uk.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Browse directory</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Abort requested: Waiting for current operation to finish...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automated Synchronisation</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Error Code %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Error resolving symbolic link:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Cannot resolve symbolic link %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Error reading from synchronisation database:</target>
+<source>Cannot read file %x.</source>
+<target>Cannot read file %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Error writing to synchronisation database:</target>
+<source>Cannot write file %x.</source>
+<target>Cannot write file %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Incompatible synchronisation database format:</target>
+<source>Database file %x is incompatible.</source>
+<target>Database file %x is incompatible.</target>
<source>Initial synchronization:</source>
<target>Initial synchronisation:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>One of the FreeFileSync database files is not yet existing:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Database file %x does not yet exist.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Database files do not share a common synchronisation session:</target>
+<source>Out of memory!</source>
+<target>Out of memory!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Database files do not share a common session.</target>
<source>An exception occurred!</source>
<target>An exception occurred!</target>
-<source>Error reading file attributes:</source>
-<target>Error reading file attributes:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Cannot read file attributes of %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Cannot get process information.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Waiting while directory is locked (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Error setting directory lock:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Cannot set directory lock %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sec</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Error reading file:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Error parsing file %x, row %y, column %z.</target>
<source>Scanning:</source>
<target>Scanning:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Invalid FreeFileSync config file!</target>
+<source>/sec</source>
+<target>/sec</target>
-<source>Error parsing configuration file:</source>
-<target>Error parsing configuration file:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>File %x does not contain a valid configuration.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configuration loaded partially only:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Configuration file %x loaded partially only.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Unable to move %x to the Recycle Bin!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Cannot access Volume Shadow Copy Service.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Please use FreeFileSync 64-bit version to create shadow copies on this system.</target>
<source>Cannot load file %x.</source>
<target>Cannot load file %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Error accessing Volume Shadow Copy Service!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Cannot determine volume name for file:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Path %x does not contain a volume name.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Volume name %x not part of file name %y!</target>
-<source>/sec</source>
-<target>/sec</target>
-
-<source>File does not exist:</source>
-<target>File does not exist:</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>
@@ -303,9 +306,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>RealtimeSync configuration</target>
-<source>File already exists. Overwrite?</source>
-<target>File already exists. Overwrite?</target>
-
<source>&Restore</source>
<target>&Restore</target>
@@ -351,32 +351,38 @@ The command line is executed each time:
<source>FreeFileSync Batch Job</source>
<target>FreeFileSync Batch Job</target>
-<source>Unable to create log file!</source>
-<target>Unable to create log file!</target>
-
<source>Batch execution</source>
<target>Batch execution</target>
-<source>Stop</source>
-<target>Stop</target>
+<source>Items processed:</source>
+<target>Elements processed:</target>
+
+<source>Items remaining:</source>
+<target>Elements remaining:</target>
<source>Total time:</source>
<target>Total time:</target>
+<source>Stop</source>
+<target>Stop</target>
+
<source>Synchronization aborted!</source>
<target>Synchronisation aborted!</target>
<source>Synchronization completed with errors!</source>
<target>Synchronisation completed with errors!</target>
+<source>Nothing to synchronize!</source>
+<target>Nothing to synchronise!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronisation completed successfully!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Press "Switch" to open FreeFileSync GUI mode.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Press "Switch" to resolve issues in FreeFileSync main dialog.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Switching to FreeFileSync GUI mode...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Switching to FreeFileSync main dialog...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Unable to connect to sourceforge.net!</target>
@@ -534,9 +540,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>Elements found:</target>
-<source>Items remaining:</source>
-<target>Elements remaining:</target>
-
<source>Speed:</source>
<target>Speed:</target>
@@ -564,9 +567,6 @@ The command line is executed each time:
<source>Right</source>
<target>Right</target>
-<source>Sync setttings</source>
-<target>Sync setttings</target>
-
<source>Status feedback</source>
<target>Status feedback</target>
@@ -591,8 +591,8 @@ The command line is executed each time:
<source>&Load</source>
<target>&Load</target>
-<source>&Cancel</source>
-<target>&Cancel</target>
+<source>Cancel</source>
+<target>Cancel</target>
<source>Select variant:</source>
<target>Select variant:</target>
@@ -642,8 +642,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>Conflict/file cannot be categorised</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Compare by...</target>
@@ -678,9 +678,6 @@ is the same
<source>Synchronizing...</source>
<target>Synchronising...</target>
-<source>Items processed:</source>
-<target>Elements processed:</target>
-
<source>&Pause</source>
<target>&Pause</target>
@@ -1020,9 +1017,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>File list exported!</target>
-<source>Error writing file:</source>
-<target>Error writing file:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1068,21 +1062,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>Paused</target>
+<source>Initializing...</source>
+<target>Initialising...</target>
+
<source>Aborted</source>
<target>Aborted</target>
<source>Completed</source>
<target>Completed</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abort requested: Waiting for current operation to finish...</target>
+<source>Continue</source>
+<target>Continue</target>
<source>Pause</source>
<target>Pause</target>
-<source>Continue</source>
-<target>Continue</target>
-
<source>Cannot find %x</source>
<target>Cannot find %x</target>
@@ -1221,68 +1215,65 @@ Exclude: \stuff\temp\*
<pluralform>%x days</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Could not initialise directory monitoring:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Error when monitoring directories.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Cannot monitor directory %x.</target>
<source>Conversion error:</source>
<target>Conversion error:</target>
-<source>Error deleting file:</source>
-<target>Error deleting file:</target>
+<source>Cannot delete file %x.</source>
+<target>Cannot delete file %x.</target>
-<source>Error moving file:</source>
-<target>Error moving file:</target>
+<source>The file is locked by another process:</source>
+<target>The file is locked by another process:</target>
-<source>Target file already existing!</source>
-<target>Target file already existing!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Cannot move file %x to %y.</target>
-<source>Error moving directory:</source>
-<target>Error moving directory:</target>
+<source>Cannot delete directory %x.</source>
+<target>Cannot delete directory %x.</target>
-<source>Target directory already existing!</source>
-<target>Target directory already existing!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Cannot write modification time of %x.</target>
-<source>Error deleting directory:</source>
-<target>Error deleting directory:</target>
+<source>Cannot find system function %x.</source>
+<target>Cannot find system function %x.</target>
-<source>Error changing modification time:</source>
-<target>Error changing modification time:</target>
+<source>Cannot read security context of %x.</source>
+<target>Cannot read security context of %x.</target>
-<source>Error loading library function:</source>
-<target>Error loading library function:</target>
+<source>Cannot write security context of %x.</source>
+<target>Cannot write security context of %x.</target>
-<source>Error reading security context:</source>
-<target>Error reading security context:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Cannot read permissions of %x.</target>
-<source>Error writing security context:</source>
-<target>Error writing security context:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Cannot write permissions of %x.</target>
-<source>Error copying file permissions:</source>
-<target>Error copying file permissions:</target>
+<source>Cannot create directory %x.</source>
+<target>Cannot create directory %x.</target>
-<source>Error creating directory:</source>
-<target>Error creating directory:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Cannot copy symbolic link %x to %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Error copying symbolic link:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Cannot write file attributes of %x.</target>
-<source>Error copying file:</source>
-<target>Error copying file:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Cannot copy file %x to %y.</target>
-<source>Error opening file:</source>
-<target>Error opening file:</target>
+<source>Cannot read directory %x.</source>
+<target>Cannot read directory %x.</target>
-<source>Error traversing directory:</source>
-<target>Error traversing directory:</target>
+<source>Endless loop.</source>
+<target>Endless loop.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Endless loop when traversing directory:</target>
+<source>Cannot set privilege %x.</source>
+<target>Cannot set privilege %x.</target>
-<source>Error setting privilege:</source>
-<target>Error setting privilege:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Unable to move %x to the Recycle Bin!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Both sides have changed since last synchronisation!</target>
@@ -1308,8 +1299,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>You can ignore this error to consider the directory as empty.</target>
-<source>Directory does not exist:</source>
-<target>Directory does not exist:</target>
+<source>Cannot find directory %x.</source>
+<target>Cannot find directory %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Directories are dependent! Be careful when setting up synchronisation rules:</target>
@@ -1317,20 +1308,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Preparing synchronisation...</target>
-<source>Out of memory!</source>
-<target>Out of memory!</target>
+<source>Conflict detected:</source>
+<target>Conflict detected:</target>
<source>File %x has an invalid date!</source>
<target>File %x has an invalid date!</target>
-<source>Conflict detected:</source>
-<target>Conflict detected:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Files %x have the same date but a different size!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Symlinks %x have the same date but a different target!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Symbolic links %x have the same date but a different target.</target>
<source>Comparing content of files %x</source>
<target>Comparing content of files %x</target>
@@ -1413,12 +1401,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>Creating file %x</target>
-<source>Creating folder %x</source>
-<target>Creating folder %x</target>
-
<source>Creating symbolic link %x</source>
<target>Creating symbolic link %x</target>
+<source>Creating folder %x</source>
+<target>Creating folder %x</target>
+
<source>Overwriting file %x</source>
<target>Overwriting file %x</target>
@@ -1437,8 +1425,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Directory for file versioning was not supplied!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Source directory does not exist anymore:</target>
+<source>Source directory %x not found.</source>
+<target>Source directory %x not found.</target>
<source>Unresolved conflicts existing!</source>
<target>Unresolved conflicts existing!</target>
@@ -1473,12 +1461,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>Generating database...</target>
-<source>Nothing to synchronize!</source>
-<target>Nothing to synchronise!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Unable to copy locked file %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Data verification error: Source and target file have different content!</target>
diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng
index aaaf3d35..48cfc636 100644
--- a/BUILD/Languages/finnish.lng
+++ b/BUILD/Languages/finnish.lng
@@ -19,11 +19,14 @@
<source>Browse directory</source>
<target>Selaa hakemistoa</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Keskeytys pyydetty: Odotetaan toiminnon loppumista...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
-<target>RealtimeSync - Automaattinen täsmäytys</target>
+<target>RealtimeSync - Automaattisoitu täsmäytys</target>
<source>Select alternate comparison settings</source>
-<target>Valitse vaihtoehtoinen vertailuasetus</target>
+<target>Valitse toinen asetus vertailulle</target>
<source>Select alternate synchronization settings</source>
<target>Valitse täsmäykselle toinen asetus</target>
@@ -83,7 +86,7 @@
<target>Näytä Pop-Up</target>
<source>Show pop-up on errors or warnings</source>
-<target>Näytä Pop-Up (virheet, varoitukset)</target>
+<target>Näytä Pop-Up (virheet/varoitukset)</target>
<source>Ignore errors</source>
<target>Älä huomioi virheitä</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux virhekoodi %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Virhe selvittäessä pikakuvaketta:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Tämä linkki on virheellinen %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x tavua</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Virhe lukiessa täsmäyksen tietokantaa:</target>
+<source>Cannot read file %x.</source>
+<target>Lukeminen ei onnistu %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Virhe kirjottaessa täsmäyksen tietokantaa:</target>
+<source>Cannot write file %x.</source>
+<target>Kirjoittaminen ei onnistu %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Täsmäytyksen tietokannan muoto on virheellinen:</target>
+<source>Database file %x is incompatible.</source>
+<target>Tietokanta %x vierasta muotoa.</target>
<source>Initial synchronization:</source>
<target>Ensi täsmäytys:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Jokin FreeFileSynk tietokannan tiedostoista puuttuu vielä:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Tietokanta %x on vielä luomatta.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Kannan tiedostot ovat eri sessioista:</target>
+<source>Out of memory!</source>
+<target>Muisti loppui!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Tietokannan tiedostot eri sessioista.</target>
<source>An exception occurred!</source>
<target>Virhe havaittu!</target>
-<source>Error reading file attributes:</source>
-<target>Virhe lukiessa tiedoston ominaisuuksia:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>x% -ominaisuudet ei tunnisteta.</target>
+
+<source>Cannot get process information.</source>
+<target>Prosessin tietoja ei saada.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Odotan hakemiston lukitusta (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Virhe asettaessa hakemiston lukkoa:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Hakemistoa %x ei saada lukittua.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,11 +184,11 @@
<pluralform>%x s</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Virhe lukiessa tiedostoa:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Virhe jäsennys tiedo %x, rivi %y, sarake %z.</target>
<source>Scanning:</source>
-<target>Haen:</target>
+<target>Skannaus:</target>
<source>Encoding extended time information: %x</source>
<target>Tulkitaan laajennettua aikatietoa: %x</target>
@@ -193,38 +202,32 @@
<pluralform>[%x säikeitä]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Virheellinen FreeFileSync asetustiedosto!</target>
+<source>/sec</source>
+<target>/s</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Tiedosto %x ei sisällä kelvollista kokoonpanoa.</target>
-<source>Error parsing configuration file:</source>
-<target>Virhe jäsentäessä asetustiedostoa:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Kokoonpanotiedosto %x ladattu vain osittain.</target>
-<source>Configuration loaded partially only:</source>
-<target>Asetukset ladattiin vain osittain:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Ei voi käyttää Volume Shadow Copy Service.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ei voitu siirtää %x Roskakoriin!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Tilannevedoksia varten käytä tässä järjestelmässä FreeFileSync 64-bittinen versio.</target>
<source>Cannot load file %x.</source>
<target>Tiedostoa %x ei voida ladata.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Virhe kutsuttaessa Volume Shadow Services!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>WOW64 varjokopiointia ei tueta. Käytä FreeFileSync 64-bittistä versiota.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Asemaa ei tunnisteta tiedostolle:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Polku %x ei sisällä taltion nimeä.</target>
<source>Volume name %x not part of file name %y!</source>
-<target>Osan nimi %x ei esiinny tiedostonimessä %y!</target>
+<target>Taltion nimi %x ei esiinny tiedostonimessä %y!</target>
-<source>/sec</source>
-<target>/s</target>
-
-<source>File does not exist:</source>
-<target>Tiedosto puuttuu:</target>
+<source>Cannot find file %x.</source>
+<target>Tiedosto %x ei löydy.</target>
<source>Cannot read the following XML elements:</source>
<target>XML elementit lukukelvottimia:</target>
@@ -268,9 +271,9 @@ The command line is executed each time:
- files within these directories or subdirectories are modified
</source>
<target>
-Komento suoritetaan kun:
-- nämä hakemistot ovat saatavilla (esim. USB tikku asennetaan)
-- tiedostot näissä hakemistoissa tai alihakemistoissa muutetaan
+Komentokehoite suoritetaan kun:
+- Kaikki hakemistot ovat saatavilla (esim. USB tikku asennetaan)
+- Tiedostot näissä hakemistoissa tai alihakemistoissa muutetaan
</target>
<source>Directories to watch</source>
@@ -289,7 +292,7 @@ Komento suoritetaan kun:
<target>Komentokehote</target>
<source>Minimum Idle Time [seconds]</source>
-<target>Minimi joutoaika [sekuntia]</target>
+<target>Minimi joutoaika [sekunttia]</target>
<source>Idle time between detection of last change and execution of command line in seconds</source>
<target>Joutoaika viimeisen muutos havainnon ja käskyn suorittamisen välillä, sekunneissa</target>
@@ -303,9 +306,6 @@ Komento suoritetaan kun:
<source>RealtimeSync configuration</source>
<target>RealtimeSync Asetukset</target>
-<source>File already exists. Overwrite?</source>
-<target>Tiedosto on jo olemassa. Ylikirjoitetaanko?</target>
-
<source>&Restore</source>
<target>&Palauta</target>
@@ -348,38 +348,41 @@ Komento suoritetaan kun:
<source>FreeFileSync configuration</source>
<target>FreeFileSync asetukset</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Eräajo</target>
-
-<source>Unable to create log file!</source>
-<target>Lokitiedostoa ei pystytä luomaan!</target>
-
<source>Batch execution</source>
<target>Eräajon suoritus</target>
-<source>Stop</source>
-<target>Seis</target>
+<source>Items processed:</source>
+<target>Osia käsitelty:</target>
+
+<source>Items remaining:</source>
+<target>Osia jäljellä:</target>
<source>Total time:</source>
<target>Kokonaisaika:</target>
+<source>Stop</source>
+<target>Seis</target>
+
<source>Synchronization aborted!</source>
<target>Täsmäytys lopetettiin!</target>
<source>Synchronization completed with errors!</source>
<target>Täsmäytys päättyi virheisiin!</target>
+<source>Nothing to synchronize!</source>
+<target>Ei mitään täsmäytettävää!</target>
+
<source>Synchronization completed successfully!</source>
<target>Täsmäytys suoritettu onnistuneesti!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Paina "Vaihda" Avaa FreeFileSync GUI toimintoa.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Paina "Vaihda" ja korjaa virheet FreeFileSync päävalintaikkunassa</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Siirtyminen FreeFileSync GUI toimintoon...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Siiry FreeFileSync päävalintaikkunaan ...</target>
<source>Unable to connect to sourceforge.net!</source>
-<target>Kytkeytyminen ei onnistu kohteeseen sourceforge.net!</target>
+<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>
@@ -445,7 +448,7 @@ Komento suoritetaan kun:
<target>Lepotila</target>
<source>Hibernate</source>
-<target>Hybernaatiotila</target>
+<target>Horrostila</target>
<source>1. &Compare</source>
<target>1. &Vertaa</target>
@@ -481,7 +484,7 @@ Komento suoritetaan kun:
<target>Vertaile</target>
<source>Compare both sides</source>
-<target>Vertaile puolet keskenään</target>
+<target>Vertaile molemmat puolet</target>
<source>&Abort</source>
<target>&Lopeta</target>
@@ -534,9 +537,6 @@ Komento suoritetaan kun:
<source>Items found:</source>
<target>Osia löytyi:</target>
-<source>Items remaining:</source>
-<target>Osia jäljellä:</target>
-
<source>Speed:</source>
<target>Nopeus:</target>
@@ -550,7 +550,7 @@ Komento suoritetaan kun:
<target>Eräajo</target>
<source>Create a batch file and automate synchronization. To start in batch mode simply double-click this file or run command: FreeFileSync.exe SyncJob.ffs_batch. This can also be scheduled in your system's task planner.</source>
-<target>Luo eräajotiedosto automatisoidaksesi täsmäytyksen. Käynnistä tupla-klikkaamalla tai suorita komento: FreeFileSync.exe SyncJob.ffs_batch. Voit ajastaa eräajo Tehtävien ajoitus -toiminnolla.</target>
+<target>Luo eräajotiedosto automatisoidaksesi täsmäytyksen. Käynnistä tuplaklikkaamalla tai suorita komento: FreeFileSync.exe SyncJob.ffs_batch. Voit ajastaa eräajo Tehtävien ajoitus -toiminnolla.</target>
<source>Help</source>
<target>Ohje</target>
@@ -568,16 +568,16 @@ Komento suoritetaan kun:
<target>Tilan palaute</target>
<source>Show progress dialog</source>
-<target>Näytä etenemisen asetukset</target>
+<target>Näytä etenemä ikkuna</target>
<source>Error handling</source>
-<target>Virhe käsitellessä</target>
+<target>Virheiden käsittely</target>
<source>Maximum number of log files:</source>
<target>Lokitiedostojen enimmäismäärä:</target>
<source>Select log file directory:</source>
-<target>Hakemisto lokitiedostoille:</target>
+<target>Lokitiedoston hakemisto:</target>
<source>Batch settings</source>
<target>Eräajo asetukset</target>
@@ -588,23 +588,23 @@ Komento suoritetaan kun:
<source>&Load</source>
<target>&Lataa</target>
-<source>&Cancel</source>
-<target>&Lopeta</target>
+<source>Cancel</source>
+<target>Lopeta</target>
<source>Select variant:</source>
<target>Valitse vaihtoehto:</target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
-<target>Tunnista ja monista muutokset tietokannalla molemmille puolille. Poisto/Poikkeama/Uudelleen nimeäminan tunnistetaan automaattisesti.</target>
+<target>Tunnista ja monista muutokset tietokannalla molemmille puolille. Poistot, uudelleennimeäminen ja ristiriidat havaitaan automaattisesti.</target>
<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
-<target>Peilaava varmuuskopio. Oikeanpuoleinen hakemisto muutetaan täsmäytyksessä vastaamaan tarkasti vasenta.</target>
+<target>Vasemman peilaava varmuuskopio. Oikeanpuoleinen hakemisto muutetaan täsmäytyksessä vastaamaan tarkasti vasenta.</target>
<source>Copy new or updated files to right folder.</source>
-<target>Kopioidaan uudet tai muuttuneet tiedostot oikeaan hakemistoon.</target>
+<target>Kopioi uudet tai päivitetyt tiedostot oikeaan kansioon.</target>
<source>Configure your own synchronization rules.</source>
-<target>Määrittele oma täsmäyssääntö.</target>
+<target>Määritä omat täsmäyssäännöt.</target>
<source>Deletion handling</source>
<target>Poistotapa</target>
@@ -625,22 +625,22 @@ Komento suoritetaan kun:
<target>Tiedosto/hakemisto löytyy vain vasemmalta</target>
<source>File/folder exists on right side only</source>
-<target>Tiedosto/hakemisto löytyy vain vasemmalta</target>
+<target>Tiedosto/hakemisto löytyy vain oiealta</target>
<source>Left file is newer</source>
-<target>Tiedosto vasemmalla on uudempi</target>
+<target>Vasen tiedosto uudempi</target>
<source>Right file is newer</source>
-<target>Tiedosto oikealla on uudempi</target>
+<target>Oikea tiedosto uudempi</target>
<source>Files have different content</source>
-<target>Tiedostojen sisältö on eri</target>
+<target>Tiedostojen sisältö on erilaisia</target>
<source>Conflict/file cannot be categorized</source>
<target>Poikkeaman/tiedoston luokittelu ei onnistu</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Vertaile...</target>
@@ -675,9 +675,6 @@ on sama
<source>Synchronizing...</source>
<target>Täsmäytetään...</target>
-<source>Items processed:</source>
-<target>Osia käsitelty:</target>
-
<source>&Pause</source>
<target>&Keskeytä</target>
@@ -685,7 +682,7 @@ on sama
<target>Koodikieli on C++ käyttäen:</target>
<source>Feedback and suggestions are welcome</source>
-<target>Palaute ja uudet ideat ovat mieluisia</target>
+<target>Palaute ja uudet ideat ovat tervetulleita</target>
<source>Homepage</source>
<target>Kotisivu</target>
@@ -697,7 +694,7 @@ on sama
<target>S-posti</target>
<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Suuret kiitokset FreeFileSync:n kääntämisestä:</target>
+<target>Suuret kiitokset FreeFileSync:n paikallistamisesta:</target>
<source>If you like FreeFileSync</source>
<target>Jos pidät FreeFileSync:tä</target>
@@ -721,7 +718,7 @@ on sama
<target>&Uudestaan</target>
<source>Do not show this dialog again</source>
-<target>Älä näytä tätä jatkossa</target>
+<target>Älä enää näytä valintaikkunaa</target>
<source>&Switch</source>
<target>&Vaihda</target>
@@ -739,15 +736,15 @@ on sama
<target>Poista molemmilta puolilta</target>
<source>Delete on both sides even if the file is selected on one side only</source>
-<target>Poista molemmilta puolilta vaikka tiedosto valittu vain toisella puolella</target>
+<target>Poista molemmin puolin, vaikka tiedosto on valittu vain toisella puolella</target>
<source>
Only files that match all filter settings will be synchronized.
Note: File names must be relative to base directories!
</source>
<target>
-Vain ne tiedostot jotka täyttää kaikkia suotimia täsmennetään.
-HUOM: Tiedostonimet oltava suhteellisia hakemistoon!
+Vain tiedostot, jotka vastaavat kaikkia suodattimen asetuksia synkronoidaan.
+Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
</target>
<source>Hints:</source>
@@ -775,7 +772,7 @@ Sulje pois: \stuff\temp\*
</target>
<source>Synchronize all .doc, .zip and .exe files except everything in subfolder "temp".</source>
-<target>Täsmäytä kaikki .doc, .zip und .exe tiedostot paitsi hakemistossa "temp" olevat.</target>
+<target>Täsmäytä kaikki .doc, .zip und .exe tiedostot paitsi kaikki hakemistossa "temp" olevat.</target>
<source>Include</source>
<target>Sisällytä</target>
@@ -802,7 +799,7 @@ Sulje pois: \stuff\temp\*
<target>Transaktio pohjainen kopiointi</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>Kirjoittaa ensin tilapäistiedostoon (*.ffs_tmp) ja nimeä sen uudestaan. Varmistaa eheyden myös Fataali Virheen tapahtuessa.</target>
+<target>Kirjoittaa ensin tilapäistiedostoon (*.ffs_tmp) ja nimeä sen uudestaan. Varmistaa eheyden myös Vakavan Virheen tapahtuessa.</target>
<source>Copy locked files</source>
<target>Kopioi lukitut tiedostot</target>
@@ -817,7 +814,7 @@ Sulje pois: \stuff\temp\*
<target>Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia)</target>
<source>Restore hidden dialogs</source>
-<target>Palauta piilotetut käskyt</target>
+<target>Palauta piilotetut ikkunat</target>
<source>External applications</source>
<target>Ulkopuolinen sovellus</target>
@@ -844,7 +841,7 @@ Sulje pois: \stuff\temp\*
<target>Toiminto lopetettiin!</target>
<source>Main bar</source>
-<target>Päävalikko</target>
+<target>Pääpalkki</target>
<source>Folder pairs</source>
<target>Hakemistoparit</target>
@@ -862,7 +859,7 @@ Sulje pois: \stuff\temp\*
<target>Sulje pois, tilapäisesti</target>
<source>Include temporarily</source>
-<target>Sisällytä tilapäisesti</target>
+<target>Sisällytä, tilapäisesti</target>
<source>Exclude via filter:</source>
<target>Sulje pois suotimella:</target>
@@ -907,7 +904,7 @@ Sulje pois: \stuff\temp\*
<target>Asetukset tallennettu!</target>
<source>Never save changes</source>
-<target>Muutoksia hylätään aina</target>
+<target>Älä tallenna muutoksia</target>
<source>Save changes to current configuration?</source>
<target>Tallenna asetuksiin tehdyt muutokset?</target>
@@ -919,13 +916,13 @@ Sulje pois: \stuff\temp\*
<target>Hakemistojen vertailu ja täsmäytys</target>
<source>Hide files that exist on left side only</source>
-<target>Piilota vain vasemmalla olevat tiedostot</target>
+<target>Piilota vain vasemmalla esiintyvät tiedostot</target>
<source>Show files that exist on left side only</source>
<target>Näytä vain vasemmalla esiintyvät tiedostot</target>
<source>Hide files that exist on right side only</source>
-<target>Piilota vain oikealla olevat tiedostot</target>
+<target>Piilota vain oikealla esiintyvät tiedostot</target>
<source>Show files that exist on right side only</source>
<target>Näytä vain oikealla esiintyvät tiedostot</target>
@@ -946,13 +943,13 @@ Sulje pois: \stuff\temp\*
<target>Piilota yhteneväiset tiedostot</target>
<source>Show files that are equal</source>
-<target>Näytä yhtenevät tiedostot</target>
+<target>Näytä yhteneväiset tiedostot</target>
<source>Hide files that are different</source>
<target>Piilota erilaiset tiedostot</target>
<source>Show files that are different</source>
-<target>Näytä poikkeavat tiedostot</target>
+<target>Näytä erilaiset tiedostot</target>
<source>Hide conflicts</source>
<target>Piilota ristiriidat</target>
@@ -1006,7 +1003,7 @@ Sulje pois: \stuff\temp\*
<target>Kaikki hakemistot täsmäävät!</target>
<source>Please run a Compare first before synchronizing!</source>
-<target>Aja Tarkistus ennen täsmäystä.</target>
+<target>Suorita Vertaile ennen täsmäystä.</target>
<source>Comma separated list</source>
<target>CSV-muotoinen lista</target>
@@ -1015,10 +1012,7 @@ Sulje pois: \stuff\temp\*
<target>Selite</target>
<source>File list exported!</source>
-<target>Tiedosto lista viety!</target>
-
-<source>Error writing file:</source>
-<target>Virhe kirjottaessa tiedostoa:</target>
+<target>Tiedostolista viety!</target>
<source>
<pluralform>Object deleted successfully!</pluralform>
@@ -1057,29 +1051,29 @@ Sulje pois: \stuff\temp\*
</target>
<source>Scanning...</source>
-<target>Haen tiedostoja...</target>
+<target>Tiedostoja haetaan...</target>
<source>Comparing content...</source>
-<target>Tietosisällön vertailu...</target>
+<target>Sisällön vertailu...</target>
<source>Paused</source>
<target>Pysäytetty</target>
+<source>Initializing...</source>
+<target>Alustus...</target>
+
<source>Aborted</source>
-<target>Lopetettu</target>
+<target>Keskeytetty</target>
<source>Completed</source>
<target>Valmis</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Keskeytys pyydetty: Odotetaan toiminnon loppumista...</target>
+<source>Continue</source>
+<target>Jatka</target>
<source>Pause</source>
<target>Tauko</target>
-<source>Continue</source>
-<target>Jatka</target>
-
<source>Cannot find %x</source>
<target>En löydä %x</target>
@@ -1218,65 +1212,65 @@ Sulje pois: \stuff\temp\*
<pluralform>%x päivää</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Hakemiston tarkkailua ei voitu käynnistää:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Virhe seuratessa hakemistoa.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Hakemistoa %x ei voida tarkkaila.</target>
<source>Conversion error:</source>
-<target>Konversio virhe:</target>
+<target>Muunnosvirhe:</target>
+
+<source>Cannot delete file %x.</source>
+<target>Ei voi poistaa tiedostoa %x.</target>
-<source>Error deleting file:</source>
-<target>Virhe poistettaessa tiedostoa:</target>
+<source>The file is locked by another process:</source>
+<target>Tiedosto on toisen prosessin lukitsema:</target>
-<source>Error moving file:</source>
-<target>Virhe siirtäessä tiedostoa:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Tiedostoa %x ei voida siirtää kohtaan %y.</target>
-<source>Target file already existing!</source>
-<target>Kohde tiedosto on jo olemassa!</target>
+<source>Cannot delete directory %x.</source>
+<target>Hakemistoa %x ei voida poistaa.</target>
-<source>Error moving directory:</source>
-<target>Virhe siirtäessä hakemistoa:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Tiedoston %x muutosaikaa ei voida kirjoittaa.</target>
-<source>Target directory already existing!</source>
-<target>Haluttu tiedosto on jo olemassa!</target>
+<source>Cannot find system function %x.</source>
+<target>Järjestelmäfunktio ei löydy, %x</target>
-<source>Error deleting directory:</source>
-<target>Virhe poistettaessa hakemistoa:</target>
+<source>Cannot read security context of %x.</source>
+<target>Ei voi lukea %x -suojauskontekstia.</target>
-<source>Error changing modification time:</source>
-<target>Virhe muuttaessa tiedoston aikaa:</target>
+<source>Cannot write security context of %x.</source>
+<target>Ei voi tallentaa %x -suojauskontekstia.</target>
-<source>Error loading library function:</source>
-<target>Virhe ladattaessa kirjastotoimintoa:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Ei voi lukea %x -oikeuksia.</target>
-<source>Error reading security context:</source>
-<target>Virhe lukiessa turvatietoja:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Ei voi tallentaa %x -oikeuksia.</target>
-<source>Error writing security context:</source>
-<target>Virhe kirjottaessa turvatietoja:</target>
+<source>Cannot create directory %x.</source>
+<target>Hakemistoa %x ei voitu luoda.</target>
-<source>Error copying file permissions:</source>
-<target>Virhe kopioitaessa tiedoston oikeuksia:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Pikakuviketta %x ei voida kopioida kohtaan %y.</target>
-<source>Error creating directory:</source>
-<target>Virhe hakemistoa luotassa:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Tiedoston %x ominaisuuksia ei voitu tallentaa.</target>
-<source>Error copying symbolic link:</source>
-<target>Symbolisen linkin kopiointi epäonnistui:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Tiedostoa %x ei voida kopioida kohtaan %y.</target>
-<source>Error copying file:</source>
-<target>Virhe kopioitaessa tiedostoa:</target>
+<source>Cannot read directory %x.</source>
+<target>Hakemisto %x ei voida lukea.</target>
-<source>Error traversing directory:</source>
-<target>Virhe hakemistoa läpikäydessä:</target>
+<source>Endless loop.</source>
+<target>Ääretön silmukka.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Suorita hakemiston läpikulku jatkuvana:</target>
+<source>Cannot set privilege %x.</source>
+<target>Oikeuksia %x ei voitu asettaa.</target>
-<source>Error setting privilege:</source>
-<target>Virhe, asettaessa oikeuksia:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ei voitu siirtää %x Roskakoriin!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Molemmat puolet muuttuneet edellisestä täsmäyksestä!</target>
@@ -1302,8 +1296,8 @@ Sulje pois: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Jätää virhe huomiotta ja tulkitse hakemisto tyhjäksi.</target>
-<source>Directory does not exist:</source>
-<target>Puuttuva hakemisto:</target>
+<source>Cannot find directory %x.</source>
+<target>Hakemisto %x ei löydy.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Hakemistot riippuvuussuhteessa! Aseta täsmäyssääntöjä varovasti:</target>
@@ -1311,20 +1305,17 @@ Sulje pois: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Täsmäytys alustetaan...</target>
-<source>Out of memory!</source>
-<target>Muisti loppui!</target>
+<source>Conflict detected:</source>
+<target>Ristiriita todettu:</target>
<source>File %x has an invalid date!</source>
<target>Tiedostolla %x on virheellinen päiväys!</target>
-<source>Conflict detected:</source>
-<target>Ristiriita todettu:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Tiedostoilla %x on sama päiväys mutta eri koko!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Pikakuvakkeilla %x on sama päiväys mutta kohde on toinen!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Pikakuvikeilla %x on sama päiväys mutta osoittavat eri kohtiin.</target>
<source>Comparing content of files %x</source>
<target>Vertaa tiedostojen %x tietosisältöä</target>
@@ -1336,10 +1327,10 @@ Sulje pois: \stuff\temp\*
<target>Luodaan tiedostolista...</target>
<source>Both sides are equal</source>
-<target>Puolet ovat denttiset</target>
+<target>Puolet ovat identtiset</target>
<source>Files/folders differ in attributes only</source>
-<target>Tiedostot/hakemistot eroavat vain ominaisuuksissa</target>
+<target>Tiedostot/hakemistot eroavat vain ominaisuuksiltaan</target>
<source>Copy new file/folder to left</source>
<target>Kopioi uusi tiedosto/hakemisto vasemmalle</target>
@@ -1360,10 +1351,10 @@ Sulje pois: \stuff\temp\*
<target>Siirrä oikea tiedosto</target>
<source>Overwrite left file/folder with right one</source>
-<target>Ylikirjoita oikea tiedosto/hakemista vasemanpuolisella</target>
+<target>Ylikirjoita vasen tiedosto/hakemista oikealla olevalla</target>
<source>Overwrite right file/folder with left one</source>
-<target>Ylikirjoita oikea tiedosto/hakemista oikeannpuolisella</target>
+<target>Ylikirjoita oikea tiedosto/hakemista vasemmalla olevalla</target>
<source>Do nothing</source>
<target>Älä tee mitään</target>
@@ -1407,12 +1398,12 @@ Sulje pois: \stuff\temp\*
<source>Creating file %x</source>
<target>Luodaan tiedosto %x</target>
-<source>Creating folder %x</source>
-<target>Luo hakemisto %x</target>
-
<source>Creating symbolic link %x</source>
<target>Luodaan pikakuvake %x</target>
+<source>Creating folder %x</source>
+<target>LuoDAAN hakemisto %x</target>
+
<source>Overwriting file %x</source>
<target>Korvaa tiedosto %x</target>
@@ -1426,13 +1417,13 @@ Sulje pois: \stuff\temp\*
<target>Päivitän %x:n ominaisuudet</target>
<source>Target directory name must not be empty!</source>
-<target>Kohdehakemisto ei saa olla tyhjä!</target>
+<target>Kohdehakemiston nimi ei saa olla tyhjä!</target>
<source>Directory for file versioning was not supplied!</source>
-<target>Versioinnin hakemisto antamatta!</target>
+<target>Tiedostoversioinnin hakemisto on antamatta!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Lähdehakemisto puuttuu:</target>
+<source>Source directory %x not found.</source>
+<target>Lähdehakemisto %x ei löydy.</target>
<source>Unresolved conflicts existing!</source>
<target>Ratkaisemattomia ristiriitoja!</target>
@@ -1447,7 +1438,7 @@ Sulje pois: \stuff\temp\*
<target>Yli 50% tiedostoista kopioidaan tai poistetaan!</target>
<source>Not enough free disk space available in:</source>
-<target>Levytila ei riitä:</target>
+<target>Vapaa levytila ei riitä:</target>
<source>Free disk space required:</source>
<target>Tarvittava vapaa levytila:</target>
@@ -1456,10 +1447,10 @@ Sulje pois: \stuff\temp\*
<target>Levytilaa jäljellä:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
-<target>Roskakori puuttuu tässä polussa! Tiedostot poistetaan pysyvästi:</target>
+<target>Roskakori puuttuu näistä polusta! Tiedostot poistetaan pysyvästi:</target>
<source>A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!</source>
-<target>Moniosaisen hakemistoparin hakemisto muutetaan! Tarkista täsmäysasetuksia!</target>
+<target>Yksi moniosaisen hakemistoparin hakemisto muutetaan! Tarkista täsmäysasetuksia!</target>
<source>Processing folder pair:</source>
<target>Käsitellään hakemistoparia:</target>
@@ -1467,12 +1458,6 @@ Sulje pois: \stuff\temp\*
<source>Generating database...</source>
<target>Luodaan tietokantaa...</target>
-<source>Nothing to synchronize!</source>
-<target>Ei mitään täsmäytettävää!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Kopioimatta, lukittu tiedosto %x</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Tiedon varmennusvirhe: Lähteellä ja kohteella on eri sisältö!</target>
diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng
index cd613d6b..2fca8158 100644
--- a/BUILD/Languages/french.lng
+++ b/BUILD/Languages/french.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Parcourir le répertoire</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Abandon demandé : En attente de la fin de l'opération en cours...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Synchronisation Automatisée</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Code erreur Linux %x :</target>
-<source>Error resolving symbolic link:</source>
-<target>Erreur lors de la résolution du lien symbolique :</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Impossible de résoudre le lien symbolique %x.</target>
<source>%x MB</source>
<target>%x Mo</target>
@@ -136,35 +139,41 @@
<pluralform>%x octets</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Erreur lors de la lecture de la base de données de synchro :</target>
+<source>Cannot read file %x.</source>
+<target>Impossible de lire le fichier %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Erreur lors de l'écriture de la base de données de synchro :</target>
+<source>Cannot write file %x.</source>
+<target>Impossible d'écrire le fichier %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Format de la base de données de synchro incompatible :</target>
+<source>Database file %x is incompatible.</source>
+<target>La base de données %x n'est pas compatible.</target>
<source>Initial synchronization:</source>
<target>Première synchronisation :</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>L'un des fichiers de la base de données FreeFileSync n'existe plus :</target>
+<source>Database file %x does not yet exist.</source>
+<target>La base de données %x n'existe plus.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Les fichiers de la base de données ne font pas partie de la même session de synchronisation</target>
+<source>Out of memory!</source>
+<target>Mémoire insuffisante !</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>
<source>An exception occurred!</source>
<target>Une erreur s'est produite !</target>
-<source>Error reading file attributes:</source>
-<target>Erreur lors de la lecture des attributs du fichier :</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Impossible de lire les attributs du fichier %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Impossible d'obtenir les informations du traitement.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>En attente tant que le répertoire est verrouillé (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Erreur lors du verrouillage du répertoire :</target>
+<source>Cannot set directory lock %x.</source>
+<target>Impossible de verrouiller le répertoire %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sec</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Erreur lors de la lecture du fichier :</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Erreur lors de l'analyse du fichier %x, ligne %y, colonne %z.</target>
<source>Scanning:</source>
<target>Lecture en cours :</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Tâches]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Fichier de configuration FreeFileSync invalide !</target>
+<source>/sec</source>
+<target>/sec</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Le fichier %x ne contient pas une configuration valide.</target>
-<source>Error parsing configuration file:</source>
-<target>Erreur lors de l'analyse du fichier de configuration :</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Le fichier de configuration %x a été chargé seulement partiellement.</target>
-<source>Configuration loaded partially only:</source>
-<target>Seule une partie de la configuration a été chargée :</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Impossible d'accéder au service Volume Shadow Copy</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Impossible de déplacer %x dans la Corbeille !</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Utilisez la version FreeFileSync 64-bit pour créer des "shadow copies" sur ce système.</target>
<source>Cannot load file %x.</source>
<target>Impossible de charger le fichier %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Erreur lors de l'accès au Volume Shadow Copy Service !</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>La copie en tâche de fond sur WOW64 n'est pas possible. Utilisez pour cela la version 64 bits de FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Impossible de trouver le nom du volume du fichier :</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Le chemin %x ne contient pas de nom de volume.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Le nom de volume %x ne fait pas partie du nom de fichier %y !</target>
-<source>/sec</source>
-<target>/sec</target>
-
-<source>File does not exist:</source>
-<target>Le fichier n'existe pas :</target>
+<source>Cannot find file %x.</source>
+<target>Impossible de trouver le fichier %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Impossible de lire les données XML suivantes :</target>
@@ -303,9 +306,6 @@ La ligne de commande est exécutée chaque fois que :
<source>RealtimeSync configuration</source>
<target>Configuration RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Le fichier existe déjà. Voulez-vous le remplacer ?</target>
-
<source>&Restore</source>
<target>&Restaurer</target>
@@ -325,7 +325,7 @@ La ligne de commande est exécutée chaque fois que :
<target>Connexion</target>
<source>File time and size</source>
-<target>Date et heure de modification du fichier</target>
+<target>Heure et taille du fichier</target>
<source>File content</source>
<target>Contenu du fichier</target>
@@ -348,35 +348,38 @@ La ligne de commande est exécutée chaque fois que :
<source>FreeFileSync configuration</source>
<target>FreeFileSync configuration</target>
-<source>FreeFileSync Batch Job</source>
-<target>Traitement batch FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>Impossible de créer un fichier log !</target>
-
<source>Batch execution</source>
<target>Exécution du traitement batch</target>
-<source>Stop</source>
-<target>Arrêt</target>
+<source>Items processed:</source>
+<target>Elements traités :</target>
+
+<source>Items remaining:</source>
+<target>Elements restants :</target>
<source>Total time:</source>
<target>Durée totale :</target>
+<source>Stop</source>
+<target>Arrêt</target>
+
<source>Synchronization aborted!</source>
<target>Synchronisation abandonnée !</target>
<source>Synchronization completed with errors!</source>
<target>Synchronisation terminée avec des erreurs !</target>
+<source>Nothing to synchronize!</source>
+<target>Rien à synchroniser !</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronisation terminée avec succès !</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Appuyer sur "Changer " pour ouvrir le mode FreeFileSync GUI</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Cliquez sur "Permuter" pour résoudre les problèmes dans l'écran principal de FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Changement en mode FreeFileSync GUI...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Passage à l'écran principal de FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Impossible de se connecter à sourceforge.net !</target>
@@ -534,9 +537,6 @@ La ligne de commande est exécutée chaque fois que :
<source>Items found:</source>
<target>Elements trouvés :</target>
-<source>Items remaining:</source>
-<target>Elements restants :</target>
-
<source>Speed:</source>
<target>Vitesse :</target>
@@ -588,8 +588,8 @@ La ligne de commande est exécutée chaque fois que :
<source>&Load</source>
<target>&Charger</target>
-<source>&Cancel</source>
-<target>&Annuler</target>
+<source>Cancel</source>
+<target>Annuler</target>
<source>Select variant:</source>
<target>Choisissez une variante :</target>
@@ -639,8 +639,8 @@ La ligne de commande est exécutée chaque fois que :
<source>Conflict/file cannot be categorized</source>
<target>Conflit ou fichier indéterminé</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Comparaison par...</target>
@@ -675,9 +675,6 @@ est identique
<source>Synchronizing...</source>
<target>Synchronisation en cours...</target>
-<source>Items processed:</source>
-<target>Elements traités :</target>
-
<source>&Pause</source>
<target>&Pause</target>
@@ -1017,9 +1014,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>Liste des fichiers exportée !</target>
-<source>Error writing file:</source>
-<target>Erreur lors de l'écriture du fichier :</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>En pause</target>
+<source>Initializing...</source>
+<target>Initialisation...</target>
+
<source>Aborted</source>
<target>Abandonné</target>
<source>Completed</source>
<target>Terminé</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abandon demandé : En attente de la fin de l'opération en cours...</target>
+<source>Continue</source>
+<target>Continuer</target>
<source>Pause</source>
<target>Pause</target>
-<source>Continue</source>
-<target>Continuer</target>
-
<source>Cannot find %x</source>
<target>Impossible de trouver %x</target>
@@ -1218,65 +1212,65 @@ Exclude: \stuff\temp\*
<pluralform>%x jours</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Impossible d'initialiser la surveillance des dossiers :</target>
-
-<source>Error when monitoring directories.</source>
-<target>Erreur lors de la surveillance des répertoires.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Impossible de gérer le répertoire %x.</target>
<source>Conversion error:</source>
<target>Erreur de conversion :</target>
-<source>Error deleting file:</source>
-<target>Erreur lors de la suppression d'un fichier :</target>
+<source>Cannot delete file %x.</source>
+<target>Impossible de supprimer le fichier %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Le fichier est verrouillé par un autre process :</target>
-<source>Error moving file:</source>
-<target>Erreur lors du déplacement du fichier :</target>
+<source>Cannot move file %x to %y.</source>
+<target>Impossible de déplacer le fichier %x vers %y.</target>
-<source>Target file already existing!</source>
-<target>Le fichier de destination existe déjà !</target>
+<source>Cannot delete directory %x.</source>
+<target>Impossible de supprimer le répertoire %x.</target>
-<source>Error moving directory:</source>
-<target>Erreur lors du déplacement du répertoire :</target>
+<source>Cannot write modification time of %x.</source>
+<target>Impossible d'écrire la date de modification de %x.</target>
-<source>Target directory already existing!</source>
-<target>Le répertoire de destination existe déjà !</target>
+<source>Cannot find system function %x.</source>
+<target>Impossible de trouver la fonction système %x.</target>
-<source>Error deleting directory:</source>
-<target>Erreur lors de la suppression d'un répertoire :</target>
+<source>Cannot read security context of %x.</source>
+<target>Impossible de lire les paramètres de sécurité de %x.</target>
-<source>Error changing modification time:</source>
-<target>Erreur lors du changement de la date de modification :</target>
+<source>Cannot write security context of %x.</source>
+<target>Impossible d'écrire les paramètres de sécurité de %x.</target>
-<source>Error loading library function:</source>
-<target>Erreur lors du chargement de la bibliothèque de fonctions :</target>
+<source>Cannot read permissions of %x.</source>
+<target>Impossible de lire les permissions de %x.</target>
-<source>Error reading security context:</source>
-<target>Erreur de lecture du contexte de sécurité:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Impossible d'écrire les permissions de %x.</target>
-<source>Error writing security context:</source>
-<target>Erreur d'écriture du contexte de sécurité:</target>
+<source>Cannot create directory %x.</source>
+<target>Impossible de créer le répertoire %x.</target>
-<source>Error copying file permissions:</source>
-<target>Erreur lors de la copie des attributs système</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Impossible de copier le lien symbolique %x vers %y.</target>
-<source>Error creating directory:</source>
-<target>Erreur lors de la création d'un répertoire :</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Impossible d'écrire les attributs de fichier de %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Erreur lors de la copie du lien symbolique :</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Impossible de copier le fichier %X vers %y.</target>
-<source>Error copying file:</source>
-<target>Erreur lors de la copie du fichier :</target>
+<source>Cannot read directory %x.</source>
+<target>Impossible de lire le répertoire %x.</target>
-<source>Error traversing directory:</source>
-<target>Erreur lors du parcours du répertoire :</target>
+<source>Endless loop.</source>
+<target>Boucle infinie.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Boucle sans fin lors du parcours du répertoire :</target>
+<source>Cannot set privilege %x.</source>
+<target>Impossible de fixer le privilège %x.</target>
-<source>Error setting privilege:</source>
-<target>Erreur de paramétrage de privilège</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Impossible de déplacer %x dans la Corbeille !</target>
<source>Both sides have changed since last synchronization!</source>
<target>Les deux côtés ont changé depuis la dernière synchronisation !</target>
@@ -1302,8 +1296,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Vous pouvez ignorer cette erreur en considérant le répertoire comme vide.</target>
-<source>Directory does not exist:</source>
-<target>Le répertoire n'existe pas :</target>
+<source>Cannot find directory %x.</source>
+<target>Impossible de trouver le répertoire %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Les répertoires sont imbriqués ! Attention à la mise à jour des règles de synchronisation :</target>
@@ -1311,20 +1305,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Synchronisation en cours de préparation ...</target>
-<source>Out of memory!</source>
-<target>Mémoire insuffisante !</target>
+<source>Conflict detected:</source>
+<target>Conflit détecté :</target>
<source>File %x has an invalid date!</source>
<target>Le fichier %x a une date invalide !</target>
-<source>Conflict detected:</source>
-<target>Conflit détecté :</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Les fichiers %x ont la même date mais une taille différente !</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Le lien symbolique %x a la même date mais une destination différente !</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Le lien symbolique %x a la même date mais pas la même cible.</target>
<source>Comparing content of files %x</source>
<target>Comparaison du contenu des fichiers %x</target>
@@ -1407,12 +1398,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>Création du fichier %x</target>
-<source>Creating folder %x</source>
-<target>Création du dossier %x</target>
-
<source>Creating symbolic link %x</source>
<target>Création du lien symbolique %x</target>
+<source>Creating folder %x</source>
+<target>Création du dossier %x</target>
+
<source>Overwriting file %x</source>
<target>Remplacement du fichier %x</target>
@@ -1431,8 +1422,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Le répertoire des versions de fichiers n'a pas été indiqué !</target>
-<source>Source directory does not exist anymore:</source>
-<target>Le répertoire source n'existe plus :</target>
+<source>Source directory %x not found.</source>
+<target>Impossible de trouver le répertoire source %x.</target>
<source>Unresolved conflicts existing!</source>
<target>Il y a des conflits non résolus !</target>
@@ -1467,12 +1458,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>Génération de la base de données...</target>
-<source>Nothing to synchronize!</source>
-<target>Rien à synchroniser !</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Impossible de copier le fichier verrouillé %x !</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Erreur lors du contrôle des données : Les fichiers source et destination ont des contenus différents !</target>
diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng
index b671f599..96ebaf75 100644
--- a/BUILD/Languages/german.lng
+++ b/BUILD/Languages/german.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Verzeichnis öffnen</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Abbruch initiiert: Warte, bis aktuelle Operation beendet ist...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatisierte Synchronisation</target>
@@ -29,7 +32,7 @@
<target>Alternative Synchronisationseinstellungen auswählen</target>
<source>No filter selected</source>
-<target>Kein Filter ausgewählt</target>
+<target>Kein Filter gesetzt</target>
<source>Filter is active</source>
<target>Filter ist aktiv</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Fehlercode %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Fehler beim Auflösen des Symbolischen Links:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Der Symbolische Link %x kann nicht aufgelöst werden.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Fehler beim Lesen der Synchronisationsdatenbank:</target>
+<source>Cannot read file %x.</source>
+<target>Die Datei %x kann nicht gelesen werden.</target>
-<source>Error writing to synchronization database:</source>
-<target>Fehler beim Schreiben der Synchronisationsdatenbank:</target>
+<source>Cannot write file %x.</source>
+<target>Die Datei %x kann nicht geschrieben werden.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Inkompatibles Datenbankformat:</target>
+<source>Database file %x is incompatible.</source>
+<target>Die Datenbankdatei %x ist nicht kompatibel.</target>
<source>Initial synchronization:</source>
<target>Erstmalige Synchronisation:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Eine der FreeFileSync Datenbankdateien existiert noch nicht:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Die Datenbankdatei %x existiert noch nicht.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Die Datenbankdateien enthalten keine gemeinsame Synchronisationssitzung:</target>
+<source>Out of memory!</source>
+<target>Nicht genügend Arbeitsspeicher!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Die Datenbankdateien teilen keine gemeinsame Sitzung.</target>
<source>An exception occurred!</source>
<target>Eine Ausnahme ist aufgetreten!</target>
-<source>Error reading file attributes:</source>
-<target>Fehler beim Lesen der Dateiattribute:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Die Dateiattribute von %x können nicht gelesen werden.</target>
+
+<source>Cannot get process information.</source>
+<target>Prozessinformationen können nicht gelesen werden.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Warte während Verzeichnis gesperrt ist (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Fehler beim Setzen der Verzeichnissperre:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Die Verzeichnissperre %x kann nicht gesetzt werden.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x Sek.</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Fehler beim Lesen der Datei:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Fehler beim Auswerten der Datei %x, Zeile %y, Spalte %z.</target>
<source>Scanning:</source>
<target>Suche Dateien:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Ungültige FreeFileSync Konfigurationsdatei!</target>
+<source>/sec</source>
+<target>/s</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Die Datei %x enthält keine gültige Konfiguration.</target>
-<source>Error parsing configuration file:</source>
-<target>Fehler beim Auswerten der Konfigurationsdatei:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Die Konfigurationsdatei %x wurde nur teilweise geladen.</target>
-<source>Configuration loaded partially only:</source>
-<target>Die Konfiguration wurde nur teilweise geladen:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Auf den Volumenschattenkopiedienst kann nicht zugegriffen werden.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>%x kann nicht in den Papierkorb verschoben werden!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Bitte benutzen Sie die FreeFileSync 64-Bit Version, um Schattenkopien auf diesem System zu erstellen.</target>
<source>Cannot load file %x.</source>
<target>Die Datei %x kann nicht geladen werden.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Fehler beim Zugriff auf den Volumenschattenkopiedienst!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Das Erstellen von Schattenkopien unter WOW64 wird nicht unterstützt. Bitte benutzen Sie die FreeFileSync 64-Bit Version.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Laufwerksname der Datei kann nicht ermittelt werden:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Der Pfad %x enthält keinen Laufwerksnamen.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Laufwerksname %x ist kein Teil des Dateinamens %y!</target>
-<source>/sec</source>
-<target>/s</target>
-
-<source>File does not exist:</source>
-<target>Die Datei existiert nicht:</target>
+<source>Cannot find file %x.</source>
+<target>Die Datei %x wurde nicht gefunden.</target>
<source>Cannot read the following XML elements:</source>
<target>Die folgenden XML-Elemente können nicht gelesen werden:</target>
@@ -303,9 +306,6 @@ Die Befehlszeile wird ausgeführt wenn:
<source>RealtimeSync configuration</source>
<target>RealtimeSync Konfiguration</target>
-<source>File already exists. Overwrite?</source>
-<target>Die Datei existiert bereits. Ãœberschreiben?</target>
-
<source>&Restore</source>
<target>&Wiederherstellen</target>
@@ -348,35 +348,38 @@ Die Befehlszeile wird ausgeführt wenn:
<source>FreeFileSync configuration</source>
<target>FreeFileSync Konfiguration</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Batch-Job</target>
-
-<source>Unable to create log file!</source>
-<target>Die Protokolldatei konnte nicht erstellt werden!</target>
-
<source>Batch execution</source>
<target>Batchlauf</target>
-<source>Stop</source>
-<target>Stop</target>
+<source>Items processed:</source>
+<target>Verarbeitete Elemente:</target>
+
+<source>Items remaining:</source>
+<target>Verbleibende Elemente:</target>
<source>Total time:</source>
<target>Gesamtzeit:</target>
+<source>Stop</source>
+<target>Stop</target>
+
<source>Synchronization aborted!</source>
<target>Synchronisation abgebrochen!</target>
<source>Synchronization completed with errors!</source>
<target>Synchronisation mit Fehlern abgeschlossen!</target>
+<source>Nothing to synchronize!</source>
+<target>Nichts zu synchronisieren!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronisation erfolgreich abgeschlossen!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>"Wechseln" öffnet FreeFileSync in der graphischen Ansicht.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Drücken Sie "Wechseln", um die Probleme in FreeFileSyncs Hauptdialog zu bearbeiten.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Wechsle in die graphische Ansicht...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Wechsle in FreeFileSyncs Hauptdialog...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Es konnte keine Verbindung zu Sourceforge.net aufgebaut werden!</target>
@@ -534,9 +537,6 @@ Die Befehlszeile wird ausgeführt wenn:
<source>Items found:</source>
<target>Gefundene Elemente:</target>
-<source>Items remaining:</source>
-<target>Verbleibende Elemente:</target>
-
<source>Speed:</source>
<target>Geschwindigkeit:</target>
@@ -564,9 +564,6 @@ Die Befehlszeile wird ausgeführt wenn:
<source>Right</source>
<target>Rechts</target>
-<source>Sync setttings</source>
-<target>Synchronisationseinstellungen</target>
-
<source>Status feedback</source>
<target>Statusrückmeldung</target>
@@ -591,8 +588,8 @@ Die Befehlszeile wird ausgeführt wenn:
<source>&Load</source>
<target>&Laden</target>
-<source>&Cancel</source>
-<target>&Abbrechen</target>
+<source>Cancel</source>
+<target>Abbrechen</target>
<source>Select variant:</source>
<target>Variante auswählen:</target>
@@ -642,8 +639,8 @@ Die Befehlszeile wird ausgeführt wenn:
<source>Conflict/file cannot be categorized</source>
<target>Konflikt/Datei, die nicht eingeordnet werden kann</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Vergleichen nach...</target>
@@ -678,9 +675,6 @@ gleich ist
<source>Synchronizing...</source>
<target>Synchronisiere...</target>
-<source>Items processed:</source>
-<target>Verarbeitete Elemente:</target>
-
<source>&Pause</source>
<target>&Pause</target>
@@ -1020,9 +1014,6 @@ Ausschließen: \stuff\temp\*
<source>File list exported!</source>
<target>Dateiliste exportiert!</target>
-<source>Error writing file:</source>
-<target>Fehler beim Schreiben der Datei:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1068,21 +1059,21 @@ Ausschließen: \stuff\temp\*
<source>Paused</source>
<target>Angehalten</target>
+<source>Initializing...</source>
+<target>Initialisiere...</target>
+
<source>Aborted</source>
<target>Abgebrochen</target>
<source>Completed</source>
<target>Fertig</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abbruch initiiert: Warte, bis aktuelle Operation beendet ist...</target>
+<source>Continue</source>
+<target>Fortfahren</target>
<source>Pause</source>
<target>Pause</target>
-<source>Continue</source>
-<target>Fortfahren</target>
-
<source>Cannot find %x</source>
<target>%x wurde nicht gefunden.</target>
@@ -1221,68 +1212,65 @@ Ausschließen: \stuff\temp\*
<pluralform>%x Tage</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Die Verzeichnisüberwachung konnte nicht gestartet werden:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Fehler beim Ãœberwachen der Verzeichnisse.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Das Verzeichnis %x kann nicht überwacht werden.</target>
<source>Conversion error:</source>
<target>Fehler bei Konvertierung:</target>
-<source>Error deleting file:</source>
-<target>Fehler beim Löschen der Datei:</target>
+<source>Cannot delete file %x.</source>
+<target>Die Datei %x kann nicht gelöscht werden.</target>
-<source>Error moving file:</source>
-<target>Fehler beim Verschieben der Datei:</target>
+<source>The file is locked by another process:</source>
+<target>Die Datei wird von einem anderen Prozess gesperrt:</target>
-<source>Target file already existing!</source>
-<target>Die Zieldatei existiert bereits!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Die Datei %x kann nicht nach %y verschoben werden.</target>
-<source>Error moving directory:</source>
-<target>Fehler beim Verschieben des Verzeichnisses:</target>
+<source>Cannot delete directory %x.</source>
+<target>Das Verzeichnis %x kann nicht gelöscht werden.</target>
-<source>Target directory already existing!</source>
-<target>Zielverzeichnis existiert bereits!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Die Änderungszeit von %x kann nicht geschrieben werden.</target>
-<source>Error deleting directory:</source>
-<target>Fehler beim Löschen des Verzeichnisses:</target>
+<source>Cannot find system function %x.</source>
+<target>Die Systemfunktion %x wurde nicht gefunden.</target>
-<source>Error changing modification time:</source>
-<target>Fehler beim Setzen der Dateiänderungszeit:</target>
+<source>Cannot read security context of %x.</source>
+<target>Der Sicherheitskontext von %x kann nicht gelesen werden.</target>
-<source>Error loading library function:</source>
-<target>Fehler beim Laden der Bibliotheksfunktion:</target>
+<source>Cannot write security context of %x.</source>
+<target>Der Sicherheitskontext von %x kann nicht geschrieben werden.</target>
-<source>Error reading security context:</source>
-<target>Fehler beim Lesen des Sicherheitskontextes:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Die Berechtigungen von %x können nicht gelesen werden.</target>
-<source>Error writing security context:</source>
-<target>Fehler beim Schreiben des Sicherheitskontextes:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Die Berechtigungen von %x können nicht geschrieben werden.</target>
-<source>Error copying file permissions:</source>
-<target>Fehler beim Kopieren der Dateiberechtigungen:</target>
+<source>Cannot create directory %x.</source>
+<target>Das Verzeichnis %x kann nicht erstellt werden.</target>
-<source>Error creating directory:</source>
-<target>Fehler beim Erstellen des Verzeichnisses:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Der Symbolische Link %x kann nicht nach %y kopiert werden.</target>
-<source>Error copying symbolic link:</source>
-<target>Fehler beim Kopieren des Symbolischen Links:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Die Dateiattribute von %x können nicht geschrieben werden.</target>
-<source>Error copying file:</source>
-<target>Fehler beim Kopieren der Datei:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Die Datei %x kann nicht nach %y kopiert werden.</target>
-<source>Error opening file:</source>
-<target>Fehler beim Öffnen der Datei:</target>
+<source>Cannot read directory %x.</source>
+<target>Das Verzeichnis %x kann nicht gelesen werden.</target>
-<source>Error traversing directory:</source>
-<target>Fehler beim Durchsuchen des Verzeichnisses:</target>
+<source>Endless loop.</source>
+<target>Endlosschleife.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Endlosschleife beim Lesen des Verzeichnisses:</target>
+<source>Cannot set privilege %x.</source>
+<target>Das Privileg %x kann nicht gesetzt werden.</target>
-<source>Error setting privilege:</source>
-<target>Fehler beim Setzen des Privilegs:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>%x kann nicht in den Papierkorb verschoben werden!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Beide Seiten wurden seit der letzten Synchronisation verändert!</target>
@@ -1308,8 +1296,8 @@ Ausschließen: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Dieser Fehler kann ignoriert werden, um das Verzeichnis als leer anzusehen.</target>
-<source>Directory does not exist:</source>
-<target>Das Verzeichnis existiert nicht:</target>
+<source>Cannot find directory %x.</source>
+<target>Das Verzeichnis %x wurde nicht gefunden.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Die Verzeichnisse sind voneinander abhängig! Achtung beim Festlegen der Synchronisationsregeln:</target>
@@ -1317,20 +1305,17 @@ Ausschließen: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Bereite Synchronisation vor...</target>
-<source>Out of memory!</source>
-<target>Nicht genügend Arbeitsspeicher!</target>
+<source>Conflict detected:</source>
+<target>Ein Konflikt wurde erkannt:</target>
<source>File %x has an invalid date!</source>
<target>Die Datei %x hat ein ungültiges Datum!</target>
-<source>Conflict detected:</source>
-<target>Ein Konflikt wurde erkannt:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Die Dateien %x haben dasselbe Datum, aber unterschiedliche Größen!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Die Symbolischen Links %x haben dasselbe Datum, aber ein unterschiedliches Ziel!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Die Symbolischen Links %x haben dasselbe Datum, aber ein unterschiedliches Ziel.</target>
<source>Comparing content of files %x</source>
<target>Vergleiche Inhalt der Dateien %x</target>
@@ -1413,12 +1398,12 @@ Ausschließen: \stuff\temp\*
<source>Creating file %x</source>
<target>Erstelle Datei %x</target>
-<source>Creating folder %x</source>
-<target>Erstelle Verzeichnis %x</target>
-
<source>Creating symbolic link %x</source>
<target>Erstelle Symbolischen Link %x</target>
+<source>Creating folder %x</source>
+<target>Erstelle Verzeichnis %x</target>
+
<source>Overwriting file %x</source>
<target>Ãœberschreibe Datei %x</target>
@@ -1437,8 +1422,8 @@ Ausschließen: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Das Verzeichnis für die Versionierung wurde nicht angegeben!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Quellverzeichnis existiert nicht mehr:</target>
+<source>Source directory %x not found.</source>
+<target>Das Quellverzeichnis %x wurde nicht gefunden.</target>
<source>Unresolved conflicts existing!</source>
<target>Es existieren ungelöste Konflikte!</target>
@@ -1473,12 +1458,6 @@ Ausschließen: \stuff\temp\*
<source>Generating database...</source>
<target>Erzeuge Synchronisationsdatenbank...</target>
-<source>Nothing to synchronize!</source>
-<target>Nichts zu synchronisieren!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Die gesperrte Datei %x kann nicht kopiert werden!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Verifizierungsfehler: Quell- und Zieldatei haben unterschiedlichen Inhalt!</target>
diff --git a/BUILD/Languages/greek.lng b/BUILD/Languages/greek.lng
index f2bc3878..5d1dfa8a 100644
--- a/BUILD/Languages/greek.lng
+++ b/BUILD/Languages/greek.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Αναζήτηση υποκαταλόγου</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Ζητήθηκε ματαίωση: Αναμονή για την λήξη της Ï„Ïέχουσας εÏγασίας...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Αυτοματοποιημένος ΣυγχÏονισμός</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Κωδικός Σφάλματος του Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Σφάλμα κατά την επίλυση του ÏƒÏ…Î¼Î²Î¿Î»Î¹ÎºÎ¿Ï Î´ÎµÏƒÎ¼Î¿Ï:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Ο συμβολικός δεσμός %x δεν μποÏεί να επιλυθεί</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Σφάλμα κατά την ανάγνωση από τη βάση δεδομένων συγχÏονισμοÏ:</target>
+<source>Cannot read file %x.</source>
+<target>Δεν μποÏεί να γίνει ανάγνωση του αÏχείου %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Σφάλμα κατά την εγγÏαφή στη βάση δεδομένων συγχÏονισμοÏ:</target>
+<source>Cannot write file %x.</source>
+<target>Δεν μποÏεί να γίνει εγγÏαφή του αÏχείου %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Η μοÏφή της βάσης δεδομένων συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï Î´ÎµÎ½ είναι συμβατή:</target>
+<source>Database file %x is incompatible.</source>
+<target>Το αÏχείο βάσης δεδομένων %x δεν είναι συμβατό</target>
<source>Initial synchronization:</source>
<target>ΑÏχικός συγχÏονισμός:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Μια από τις βάσεις δεδομένων του FreeFileSync δεν υπάÏχει ακόμα:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Το αÏχείο βάσης δεδομένων %x δεν υπάÏχει ακόμα.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Οι βάσεις δεδομένων δεν έχουν δημιουÏγηθεί από τον ίδιο συγχÏονισμό:</target>
+<source>Out of memory!</source>
+<target>ΑνεπαÏκής μνήμη!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Τα αÏχεία βάσης δεδομένων δεν έχουν χÏησιμοποιηθεί από ÎºÎ¿Î¹Î½Î¿Ï ÏƒÎµ συγχÏονισμό.</target>
<source>An exception occurred!</source>
<target>ΠαÏουσιάστηκε σφάλμα!</target>
-<source>Error reading file attributes:</source>
-<target>Σφάλμα κατά την ανάγνωση των χαÏακτηÏιστικών του αÏχείου:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Δεν μποÏεί να γίνει ανάγνωση των χαÏακτηÏιστικών του αÏχείου %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Δεν μποÏοÏν να ληφθοÏν πληÏοφοÏίες για τις Ï„Ïέχουσες διαδικασίες.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Αναμονή μέχÏι να κλειδωθεί ο υποκατάλογος (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Σφάλμα κατά το κλείδωμα του υποκαταλόγου:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Δεν μποÏεί να κλειδωθεί ο υπολατάλογος %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x δ/λεπτα</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Σφάλμα κατά την ανάγνωση του αÏχείου:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Σφάλμα κατά την ανάλυση του αÏχείου %x, γÏαμμή %y, στήλη %z.</target>
<source>Scanning:</source>
<target>Ανίχνευση:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Îήματα]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Το αÏχείο διάταξης του FreeFileSync δεν είναι έγκυÏο!</target>
+<source>/sec</source>
+<target>/δευτεÏόλεπτο</target>
-<source>Error parsing configuration file:</source>
-<target>Σφάλμα κατά την ανάλυση του αÏχείου διάταξης:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>Το αÏχείο %x δεν πεÏιέχει μια έγκυÏη διάταξη.</target>
-<source>Configuration loaded partially only:</source>
-<target>Μόνο ένα τμήμα του αÏχείου διάταξης φοÏτώθηκε:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Το αÏχείο διάταξης %x έχει φοÏτωθεί μόνο κατά ένα μέÏος.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Δεν ήταν δυνατό να μεταφεÏθεί το %x στον Κάδο ΑνακÏκλωσης!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Δεν πέτυχε η Ï€Ïόσφαση στην ΥπηÏεσεία Σκιώδους ΑντίγÏαφου Τόμου.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>ΧÏησιμοποιήστε την 64-μπιτη έκδοση του FreeFileSync για να δημιουÏγήσετε σκιώδη αντίγÏαφα σε αυτόν τον υπολογιστή.</target>
<source>Cannot load file %x.</source>
<target>Το αÏχείο %x δεν ήταν δυνατόν να φοÏτωθεί.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Σφάλμα κατά την Ï€Ïόσβαση στην υπηÏεσία Volume Shadow Copy!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Δεν είναι δυνατή η δημιουÏγία σκιώδους αντίγÏαφου σε WOW64. ΧÏησιμοποιείστε την 64-bit έκδοση του FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Δεν ήταν δυνατό να βÏεθεί το όνομα τόμου για το αÏχείο:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Η διαδÏομή %x δεν πεÏιέχει ένα όνομα τόμου.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Το όνομα τόμου %x δεν είναι μέÏος του ονόματος του αÏχείου %y!</target>
-<source>/sec</source>
-<target>/δευτεÏόλεπτο</target>
-
-<source>File does not exist:</source>
-<target>Το αÏχείο δεν υπάÏχει:</target>
+<source>Cannot find file %x.</source>
+<target>Το αÏχείο %x δε βÏέθηκε.</target>
<source>Cannot read the following XML elements:</source>
<target>Δεν ήταν δυνατό να αναγνωσθοÏν τα ακόλουθα στοιχεία XML:</target>
@@ -303,9 +306,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>ΔιαμόÏφωση του RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Το αÏχείο υπάÏχει ήδη. Îα αντικατασταθεί;</target>
-
<source>&Restore</source>
<target>&ΕπαναφοÏά</target>
@@ -348,35 +348,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>ΑÏχείο διάταξης FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Δέσμη ΕνεÏγειών</target>
-
-<source>Unable to create log file!</source>
-<target>Δεν είναι δυνατή η δημιουÏγία ενός αÏχείου καταγÏαφής!</target>
-
<source>Batch execution</source>
<target>Εκτέλεση δέσμης ενεÏγειών</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>Ο συγχÏονισμός ματαιώθηκε!</target>
<source>Synchronization completed with errors!</source>
<target>Ο συγχÏονισμός ολοκληÏώθηκε με σφάλματα!</target>
+<source>Nothing to synchronize!</source>
+<target>Δεν υπάÏχει τίποτα Ï€Ïος συγχÏονισμό!</target>
+
<source>Synchronization completed successfully!</source>
<target>Ο συγχÏονισμός ολοκληÏώθηκε επιτυχώς!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Πατήστε "Εναλλαγή" για να ανοίξετε το γÏαφικό πεÏιβάλλον του FreeFileSync</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Πατήστε "Εναλλαγή" για να επιλÏσετε τα θέματα στο κεντÏικό παÏάθυÏο του FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Εναλλαγή στο γÏαφικό πεÏιβάλλον του FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>ΕπιστÏέφοντας στο κεντÏικό παÏάθυÏο του FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Δεν είναι δυνατή η σÏνδεση με το sourceforge.net!</target>
@@ -534,9 +537,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>Î’Ïέθηκαν στοιχεία:</target>
-<source>Items remaining:</source>
-<target>ΠεÏισσεÏουν στοιχεία:</target>
-
<source>Speed:</source>
<target>ΤαχÏτητα:</target>
@@ -588,8 +588,8 @@ The command line is executed each time:
<source>&Load</source>
<target>&Άνοιγμα</target>
-<source>&Cancel</source>
-<target>&ΆκυÏο</target>
+<source>Cancel</source>
+<target>ΆκυÏο</target>
<source>Select variant:</source>
<target>Επιλέξτε μια μέθοδο:</target>
@@ -639,8 +639,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>Η διένεξη / το αÏχείο δεν μποÏεί να κατηγοÏιοποιηθεί</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>ΣÏγκÏιση με βάση το...</target>
@@ -675,9 +675,6 @@ is the same
<source>Synchronizing...</source>
<target>Γίνεται συγχÏονισμός...</target>
-<source>Items processed:</source>
-<target>ΕπεξεÏγάστηκαν στοιχεία:</target>
-
<source>&Pause</source>
<target>&ΠαÏση</target>
@@ -808,7 +805,7 @@ Exclude: \stuff\temp\*
<target>ΑντιγÏαφή κλειδωμένων αÏχείων</target>
<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
-<target>ΑντιγÏαφή κλειδωμένων ή διαμοιÏασμένων αÏχείων με την υπηÏεσία Volume Shadow Copy (απαιτεί δικαιώματα Administrator)</target>
+<target>ΑντιγÏαφή κλειδωμένων ή διαμοιÏασμένων αÏχείων με την YπηÏεσία Σκιώδους ΑντίγÏαφου Τόμου (απαιτεί δικαιώματα Administrator)</target>
<source>Copy file access permissions</source>
<target>ΑντιγÏαφή των αδειών Ï€Ïοσπέλασης των αÏχείων</target>
@@ -1017,9 +1014,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>Ο κατάλογος των αÏχείων έχει εξαχθεί!</target>
-<source>Error writing file:</source>
-<target>Σφάλμα κατά την εγγÏαφή του αÏχείου:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>Σε παÏση</target>
+<source>Initializing...</source>
+<target>ΑÏχικοποίηση...</target>
+
<source>Aborted</source>
<target>Ματαιώθηκε</target>
<source>Completed</source>
<target>ΟλοκληÏώθηκε</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Ζητήθηκε ματαίωση: Αναμονή για την λήξη της Ï„Ïέχουσας εÏγασίας...</target>
+<source>Continue</source>
+<target>Συνέχεια</target>
<source>Pause</source>
<target>ΠαÏση</target>
-<source>Continue</source>
-<target>Συνέχεια</target>
-
<source>Cannot find %x</source>
<target>Δεν μποÏεί να βÏεθεί το %x</target>
@@ -1218,65 +1212,65 @@ Exclude: \stuff\temp\*
<pluralform>%x μέÏες</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Δεν ήταν δυνατό να γίνει έναÏξη παÏακολοÏθησης του υποκαταλόγου:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Σφάλμα κατά την παÏακολοÏθηση υποκαταλόγων.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Δεν είναι δυνατή η παÏακολÏθηση του υποκαταλόγου %x.</target>
<source>Conversion error:</source>
<target>Σφάλμα μετατÏοπής:</target>
-<source>Error deleting file:</source>
-<target>Σφάλμα κατά τη διαγÏαφή του αÏχείου:</target>
+<source>Cannot delete file %x.</source>
+<target>Δεν μποÏεί να διαγÏαφεί το αÏχείο %x.</target>
-<source>Error moving file:</source>
-<target>Σφάλμα κατά τη μεταφοÏά του αÏχείου:</target>
+<source>The file is locked by another process:</source>
+<target>Το αÏχείο είναι κλειδωμένο από μια άλλη διαδικασία:</target>
-<source>Target file already existing!</source>
-<target>Το αÏχείο Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Ï…Ï€Î¬Ïχει ήδη!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Δεν μποÏεί το αÏχείο %x να μεταφεÏθεί στο %y.</target>
-<source>Error moving directory:</source>
-<target>Σφάλμα κατά τη μεταφοÏά του υποκαταλόγου:</target>
+<source>Cannot delete directory %x.</source>
+<target>Δεν μποÏεί να διαγÏαφεί ο υποκατάλογος %x.</target>
-<source>Target directory already existing!</source>
-<target>Ο υποκατάλογος Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Ï…Ï€Î¬Ïχει ήδη!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Δεν μποÏεί να γίνει εγγÏαφή της ÏŽÏας Ï„Ïοποποίησης του %x.</target>
-<source>Error deleting directory:</source>
-<target>Σφάλμα κατά τη διαγÏαφή του υποκαταλόγου:</target>
+<source>Cannot find system function %x.</source>
+<target>Δεν ανευÏίσκεται η λειτουÏγία συστήματος %x.</target>
-<source>Error changing modification time:</source>
-<target>Σφάλμα κατά την αλλαγή της ÏŽÏας Ï„Ïοποποίησης:</target>
+<source>Cannot read security context of %x.</source>
+<target>Δεν μποÏεί να αναγνωσθεί το πεÏιβάλλον ασφαλείας του x%.</target>
-<source>Error loading library function:</source>
-<target>Σφάλμα κατά τη φόÏτωση της συνάÏτησης βιβλιοθήκης:</target>
+<source>Cannot write security context of %x.</source>
+<target>Δεν μποÏεί να γίνει εγγÏαφή του πεÏιβάλλοντος ασφαλείας του x%.</target>
-<source>Error reading security context:</source>
-<target>Σφάλμα κατά την ανάγνωση του πλαισίου ασφαλείας:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Δεν μποÏοÏν να αναγνωσθοÏν οι άδειες Ï€Ïοσπέλασης του %x.</target>
-<source>Error writing security context:</source>
-<target>Σφάλμα κατά την εγγÏαφή του πλαισίου ασφάλειας:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Δεν μποÏεί να γίνει εγγÏαφή των αδειών Ï€Ïοσπέλασης του %x.</target>
-<source>Error copying file permissions:</source>
-<target>Σφάλμα κατά την αντιγÏαφή των αδειών των αÏχείων:</target>
+<source>Cannot create directory %x.</source>
+<target>Δεν μποÏεί να δημιουÏγηθεί ο υποκατάλογος %x.</target>
-<source>Error creating directory:</source>
-<target>Σφάλμα κατά τη δημιουÏγία του υποκαταλόγου:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Δεν μποÏεί να αντιγÏαφεί ο συμβολικός δεσμός %x στο %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Σφάλμα κατά την αντιγÏαφή του ÏƒÏ…Î¼Î²Î¿Î»Î¹ÎºÎ¿Ï Î´ÎµÏƒÎ¼Î¿Ï:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Δεν μποÏεί να γίνει εγγÏαφή των χαÏακτηÏιστικών αÏχείου του %x.</target>
-<source>Error copying file:</source>
-<target>Σφάλμα κατά την αντιγÏαφή του αÏχείου:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Δεν μποÏεί να αντιγÏαφεί το αÏχείο %x στο %y.</target>
-<source>Error traversing directory:</source>
-<target>Σφάλμα κατά την ανάλυση του υποκαταλόγου:</target>
+<source>Cannot read directory %x.</source>
+<target>Δεν μποÏεί να αναγνωσθεί ο υποκατάλογος %x.</target>
-<source>Endless loop when traversing directory:</source>
-<target>ΑτέÏμονος βÏόχος κατά την την ανάλυση του υποκαταλόγου:</target>
+<source>Endless loop.</source>
+<target>ΑτέÏμων βÏόχος.</target>
-<source>Error setting privilege:</source>
-<target>Σφάλμα κατά τον οÏισμό δικαιωμάτων:</target>
+<source>Cannot set privilege %x.</source>
+<target>Τα δικαιώματα %x δεν μποÏοÏν να οÏιστοÏν.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Το αÏχείο %x δεν μπόÏεσε να μεταφεÏθεί στον Κάδο ΑνακÏκλωσης!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Και οι δυο πλευÏές έχουν αλλάξει από τον τελευταίο συγχÏονισμό!</target>
@@ -1302,8 +1296,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>ΜποÏείτε να αγνοήσετε αυτό το σφάλμα και να θεωÏήσετε τον υποκατάλογο κενό.</target>
-<source>Directory does not exist:</source>
-<target>Ο υποκατάλογος δεν υπάÏχει:</target>
+<source>Cannot find directory %x.</source>
+<target>Ο υποκατάλογος %x δεν μποÏεί να βÏεθεί.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Οι υποκατάλογοι είναι εξαÏτώμενοι. ΠÏοσοχή κατά την εισαγωγή των κανόνων συγχÏονισμοÏ:</target>
@@ -1311,20 +1305,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>ΠÏοετοιμασία του συγχÏονισμοÏ...</target>
-<source>Out of memory!</source>
-<target>ΑνεπαÏκής μνήμη!</target>
+<source>Conflict detected:</source>
+<target>ΑνιχνεÏθηκε διένεξη:</target>
<source>File %x has an invalid date!</source>
<target>Το αÏχείο %x δεν έχει έγκυÏη ημεÏομηνία!</target>
-<source>Conflict detected:</source>
-<target>ΑνιχνεÏθηκε διένεξη:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Τα αÏχεία %x έχουν την ίδια ημεÏομηνία αλλά διαφοÏετικό μέγεθος!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Οι συμβολικοί δεσμοί %x έχουν την ίδια ημεÏομηνία αλλά διαφοÏετικό Ï€ÏοοÏισμό!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Οι συμβολικοί δεσμοί %x έχουν την ίδια ημεÏομηνία αλλά διαφοÏετικό Ï€ÏοοÏισμό.</target>
<source>Comparing content of files %x</source>
<target>ΣÏγκÏιση του πεÏιεχομένου των αÏχείων %x</target>
@@ -1407,12 +1398,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>ΔημιουÏγία του αÏχείου %x</target>
-<source>Creating folder %x</source>
-<target>ΔημιουÏγία του υποκαταλόγου %x</target>
-
<source>Creating symbolic link %x</source>
<target>ΔημιουÏγία του ÏƒÏ…Î¼Î²Î¿Î»Î¹ÎºÎ¿Ï Î´ÎµÏƒÎ¼Î¿Ï %x</target>
+<source>Creating folder %x</source>
+<target>ΔημιουÏγία του υποκαταλόγου %x</target>
+
<source>Overwriting file %x</source>
<target>Αντικατάσταση του αÏχείου %x</target>
@@ -1431,8 +1422,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Δεν έχει οÏιστεί υποκατάλογος για τη διατήÏηση παλιών εκδόσεων!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Ο υποκατάλογος Ï€Ïοέλευσης δεν υπάÏχει πλέον:</target>
+<source>Source directory %x not found.</source>
+<target>Ο υποκατάλογος πηγής %x δεν βÏέθηκε.</target>
<source>Unresolved conflicts existing!</source>
<target>ΥπάÏχουν ανεπίλυτες διενέξεις!</target>
@@ -1467,12 +1458,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>ΔημιουÏγία βάσης δεδομένων...</target>
-<source>Nothing to synchronize!</source>
-<target>Δεν υπάÏχει τίποτα Ï€Ïος συγχÏονισμό!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Δεν ήταν δυνατό να αντιγÏαφεί το κλειδωμένο αÏχείο %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Σφάλμα επικÏÏωσης δεδομένων: Τα αÏχεία Ï€Ïοέλευσης και Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Î­Ï‡Î¿Ï…Î½ διαφοÏετικό πεÏιεχόμενο!</target>
diff --git a/BUILD/Languages/hebrew.lng b/BUILD/Languages/hebrew.lng
index a55fd05f..7c2bb384 100644
--- a/BUILD/Languages/hebrew.lng
+++ b/BUILD/Languages/hebrew.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>עיין במחיצה</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>התקבלה בקשת ביטול: מחכה לפעולה הנוכחית להסתיי×...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - סינכרון ×וטומטי</target>
+<source>Error</source>
+<target>שגי××”</target>
+
<source>Select alternate comparison settings</source>
<target>בחר הגדרות השוו××” חליפיות</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>×ודות</target>
-<source>Error</source>
-<target>שגי××”</target>
-
<source>Warning</source>
<target>×זהרה</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>קוד שגי×ת לינוקס %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>שגי××” בפענוח קישור סימבולי (Symbolic Link)</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>×œ× ×™×›×•×œ לפענח ×ת הקישור הסימבולי %x.</target>
<source>%x MB</source>
<target>%x מגה בייט</target>
@@ -136,35 +139,41 @@
<pluralform>%x בייט</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>שגי××” בקרי××” מבסיס ×”× ×ª×•× ×™× ×©×œ הסנכרון:</target>
+<source>Cannot read file %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×§×•×‘×¥ %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>שגי××” ×‘×¨×™×©×•× ×œ×‘×¡×™×¡ נתוני סנכרון:</target>
+<source>Cannot write file %x.</source>
+<target>×œ× ×™×›×•×œ לכתוב קובץ %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>מסד × ×ª×•× ×™× ×©×œ הסנכרון ×œ× ×ª×•××:</target>
+<source>Database file %x is incompatible.</source>
+<target>קובץ בסיס × ×ª×•× ×™× %x ×ינו במבנה מת××™×.</target>
<source>Initial synchronization:</source>
<target>סנכרון ר×שוני:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>×חד מקובצי בסיס ×”× ×ª×•× ×™× ×”×‘× ×¢×“×™×™×Ÿ ×œ× ×§×™×™×</target>
+<source>Database file %x does not yet exist.</source>
+<target>קובץ בסיס × ×ª×•× ×™× %x ×ינו ×§×™×™× ×¢×“×™×™×Ÿ.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>קבצי בסיס ×”× ×ª×•× ×™× ××™× × ×—×•×œ×§×™× ×רוע סנכרון משותף:</target>
+<source>Out of memory!</source>
+<target>×ª× ×”×–×›×¨×•×Ÿ!</target>
+
+<source>Database files do not share a common session.</source>
+<target>קבצי ×”× ×ª×•× ×™× ××™× × ×›×•×œ×œ×™× ×ž×•×¤×¢ פעילות משותף.</target>
<source>An exception occurred!</source>
<target>×ירוע חריג!</target>
-<source>Error reading file attributes:</source>
-<target>שגי××” בקרי×ת תכונות קובץ:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×ª×›×•× ×•×ª של קובץ %x.</target>
+
+<source>Cannot get process information.</source>
+<target>×œ× ×™×›×•×œ לקבל ×ת נתוני התהליך.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>ממתין ×›×שר מחיצה נעולה (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>שגי××” בנעילת מחיצה:</target>
+<source>Cannot set directory lock %x.</source>
+<target>×œ× ×™×›×•×œ להגדיר ×ת נעילת מחיצה %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x שניות</pluralform>
</target>
-<source>Error reading file:</source>
-<target>שגי××” בקרי×ת קובץ:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>שגי××” בפענוח קובץ %x, שורה %y, טור %z.</target>
<source>Scanning:</source>
<target>סורק:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x תהליכוני×]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>קובץ תצורה בלתי חוקי!</target>
+<source>/sec</source>
+<target>/שנ</target>
-<source>Error parsing configuration file:</source>
-<target>שגי××” בניתוח קובץ תצורה:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>קובץ %x ×ינו כולל תצורה תקינה.</target>
-<source>Configuration loaded partially only:</source>
-<target>תצורה נטענה חלקית בלבד:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>קובץ תצורה %x נטען חלקית בלבד.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>×œ× ×™×›×•×œ להעביר ×ת %x לסל המיחזור!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>×œ× ×™×›×•×œ לגשת ×ל volume shadow copy service.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>×× × ×”×©×ª×ž×© בגירסת 64-bit של FreeFileSync על מנת ליצר shadow copies במערכת הפעלה זו.</target>
<source>Cannot load file %x.</source>
<target>×œ× ×™×›×•×œ לטעון קובץ %x!</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>שגי××” בגישה לשרות Volume Shadow Copy Service</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>×œ× × ×ª×ž×›×ª בגרסה ×–×ת ×× × ×”×ª×§×Ÿ גרסה 64 WOW64 העתקת צל ב</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>×œ× ×™×›×•×œ לקבוע ×©× ×›×•× ×Ÿ עבור קובץ:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>נתיב %x ×ינו כולל ×©× ×›×¨×š.</target>
<source>Volume name %x not part of file name %y!</source>
<target>ככונן %x ×œ× ×‘× ×ª×™×‘ של קובץ %y!</target>
-<source>/sec</source>
-<target>/שנ</target>
-
-<source>File does not exist:</source>
-<target>קובץ ×œ× ×§×™×™×:</target>
+<source>Cannot find file %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×ž×¦×•× ×§×•×‘×¥ %x.</target>
<source>Cannot read the following XML elements:</source>
<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×ת שמות צמתי XML:</target>
@@ -297,15 +300,18 @@ The command line is executed each time:
<source>Start</source>
<target>התחל</target>
+<source>&Retry</source>
+<target>&נסה שנית</target>
+
+<source>Cancel</source>
+<target>בטל</target>
+
<source>(Build: %x)</source>
<target>(מבנה: %x)</target>
<source>RealtimeSync configuration</source>
<target>RealtimeSync בקרת תצורה</target>
-<source>File already exists. Overwrite?</source>
-<target>קובץ ×§×™×™× ×”×× ×œ×“×¨×•×¡?</target>
-
<source>&Restore</source>
<target>&טען מחדש</target>
@@ -348,35 +354,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>FreeFileSync הגדרות</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync עבודת ×צווה</target>
-
-<source>Unable to create log file!</source>
-<target>×œ× ×ž×¡×•×’×œ ליצור קובץ יומן!</target>
-
<source>Batch execution</source>
<target>פעולת ×צווה</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>סינכרון בוטל!</target>
<source>Synchronization completed with errors!</source>
<target>סנכרון ×”×•×©×œ× ×¢× ×©×’×™×ות!</target>
+<source>Nothing to synchronize!</source>
+<target>×ין מה לסנכרן!</target>
+
<source>Synchronization completed successfully!</source>
<target>סינכרון ×”×•×©×œ× ×‘×”×¦×œ×—×”!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>"לחץ" לפתיחת FreeFileSync בממשק גרפי.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>לחץ על "החלפה" בכדי לפתור בעיות בדי×לוג הר×שי.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>החלף לתצורת ממשק חזותי...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>עובר לדי×לוג הר×שי של FreeFileSync</target>
<source>Unable to connect to sourceforge.net!</source>
<target>×ין תקשורת ל sourceforge.net!</target>
@@ -534,9 +543,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>××œ×ž× ×˜×™× × ×ž×¦×ו:</target>
-<source>Items remaining:</source>
-<target>××œ×ž× ×ª×™× × ×•×ª×¨×•:</target>
-
<source>Speed:</source>
<target>מהירות:</target>
@@ -588,9 +594,6 @@ The command line is executed each time:
<source>&Load</source>
<target>&טען</target>
-<source>&Cancel</source>
-<target>&בטל</target>
-
<source>Select variant:</source>
<target>בחר משתנה:</target>
@@ -639,8 +642,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>קונפליקט\קובץ ×ינו יכול לקבל סיווג</target>
-<source>&OK</source>
-<target>&×שר</target>
+<source>OK</source>
+<target>×שר</target>
<source>Compare by...</source>
<target>השווה ע"י...</target>
@@ -675,9 +678,6 @@ is the same
<source>Synchronizing...</source>
<target>מסנכרן...</target>
-<source>Items processed:</source>
-<target>××œ×ž× ×˜×™× ×¢×•×‘×“×•:</target>
-
<source>&Pause</source>
<target>&עצור</target>
@@ -717,9 +717,6 @@ is the same
<source>&Ignore</source>
<target>&התעל×</target>
-<source>&Retry</source>
-<target>&נסה שנית</target>
-
<source>Do not show this dialog again</source>
<target>×ל תר××” מסך ×–×” שנית</target>
@@ -1017,9 +1014,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>רשימת ×§×‘×¦×™× ×™×•×¦××”!</target>
-<source>Error writing file:</source>
-<target>שגי××” בכתיבת קובץ:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>עצור</target>
+<source>Initializing...</source>
+<target>מ×תחל ...</target>
+
<source>Aborted</source>
<target>הופסק</target>
<source>Completed</source>
<target>הושל×</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>התקבלה בקשת ביטול: מחכה לפעולה הנוכחית להסתיי×...</target>
+<source>Continue</source>
+<target>המשך</target>
<source>Pause</source>
<target>עצור</target>
-<source>Continue</source>
-<target>המשך</target>
-
<source>Cannot find %x</source>
<target>×œ× ×ž×•×¦× %x</target>
@@ -1218,65 +1212,65 @@ Exclude: \stuff\temp\*
<pluralform>%x ימי×</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>×œ× ×™×›×•×œ ל×תחל ניטור מחיצה:</target>
-
-<source>Error when monitoring directories.</source>
-<target>שגי××” בזמן ניטור מחיצות.</target>
+<source>Cannot monitor directory %x.</source>
+<target>×œ× ×™×›×•×œ לנטר מחיצה %x.</target>
<source>Conversion error:</source>
<target>שגי××” בהסבה:</target>
-<source>Error deleting file:</source>
-<target>שגי××” במחיקת קובץ:</target>
+<source>Cannot delete file %x.</source>
+<target>×œ× ×™×›×•×œ למחוק קובץ %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>הקובץ נעול ע"י תהליך:</target>
-<source>Error moving file:</source>
-<target>שגי××” בהעברת קובץ:</target>
+<source>Cannot move file %x to %y.</source>
+<target>×œ× ×™×›×•×œ להעביר קובץ %x ×ל %y.</target>
-<source>Target file already existing!</source>
-<target>קובץ מטרה כבר קיי×!</target>
+<source>Cannot delete directory %x.</source>
+<target>×œ× ×™×›×•×œ למחוק מחיצה %x.</target>
-<source>Error moving directory:</source>
-<target>שגי××” בהעברת מחיצה:</target>
+<source>Cannot write modification time of %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×¨×©×•× ×–×ž×Ÿ שינוי של %x.</target>
-<source>Target directory already existing!</source>
-<target>מחיצת מטרה כבר קיימת!</target>
+<source>Cannot find system function %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×ž×¦×•× ×¤×•× ×§×¦×™×ª מערכת %x.</target>
-<source>Error deleting directory:</source>
-<target>שגי××” במחיקת מחיצה:</target>
+<source>Cannot read security context of %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×”×§×©×¨ בטיחות של %x.</target>
-<source>Error changing modification time:</source>
-<target>שגי××” בשינוי זמן:</target>
+<source>Cannot write security context of %x.</source>
+<target>×œ× ×™×›×•×œ לכתוב הקשר בטיחות של %x.</target>
-<source>Error loading library function:</source>
-<target>שגי××” בטעינת ספרית פונקציות:</target>
+<source>Cannot read permissions of %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×”×¨×©×ות של %x.</target>
-<source>Error reading security context:</source>
-<target>שגי××” בכתיבת הקשר בטיחות:</target>
+<source>Cannot write permissions of %x.</source>
+<target>×œ× ×™×›×•×œ לכתוב הרש×ות של %x.</target>
-<source>Error writing security context:</source>
-<target>שגי××” בכתיבת הקשר בטיחות:</target>
+<source>Cannot create directory %x.</source>
+<target>×œ× ×™×›×•×œ ליצור מחיצה %x.</target>
-<source>Error copying file permissions:</source>
-<target>שגי××” בהעתקת הרש×ות קובץ:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>×œ× ×™×›×•×œ להעתיק קישור סימבולי %x ×ל %y.</target>
-<source>Error creating directory:</source>
-<target>שגי××” ביצירת מחיצה:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>×œ× ×™×›×•×œ לכתוב תכונות קובץ של %x.</target>
-<source>Error copying symbolic link:</source>
-<target>שגי××” בהעתקת קישור :</target>
+<source>Cannot copy file %x to %y.</source>
+<target>×œ× ×™×›×•×œ להעתיק קובץ %x ×ל %y.</target>
-<source>Error copying file:</source>
-<target>שגי××” בהעתקת קובץ:</target>
+<source>Cannot read directory %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×§×¨×•× ×ž×—×™×¦×” %x.</target>
-<source>Error traversing directory:</source>
-<target>שגי××” בהצלבת מחיצות</target>
+<source>Endless loop.</source>
+<target>לול××” ×ינסופית.</target>
-<source>Endless loop when traversing directory:</source>
-<target>נוצרת לול××” ×ינסופית בחצית מחיצות</target>
+<source>Cannot set privilege %x.</source>
+<target>×œ× ×™×›×•×œ להגדיר זבות %x.</target>
-<source>Error setting privilege:</source>
-<target>שגי××” בהשמת פריווילגיה</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>×œ× ×™×›×•×œ להעביר ×ת %x לסל המיחזור!</target>
<source>Both sides have changed since last synchronization!</source>
<target>שני ×”×¦×“×“×™× ×©×•× ×• מ××– הסנכרון ×”×חרון!</target>
@@ -1302,8 +1296,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>×פשר ×œ×”×ª×¢×œ× ×ž×©×’×™××” זו ולהניח ×›×™ המחיצה ריקה.</target>
-<source>Directory does not exist:</source>
-<target>מחיצה ×œ× ×§×™×™×ž×ª:</target>
+<source>Cannot find directory %x.</source>
+<target>×œ× ×™×›×•×œ ×œ×ž×¦×•× ×ž×—×™×¦×” %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>מחיצות תלויות! זהירות בהגדרת כללי סנכרון:</target>
@@ -1311,20 +1305,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>מכין סינכרון...</target>
-<source>Out of memory!</source>
-<target>×ª× ×”×–×›×¨×•×Ÿ!</target>
+<source>Conflict detected:</source>
+<target>התגלה קונפליקט:</target>
<source>File %x has an invalid date!</source>
<target>קובץ %x מכיל ת×ריך שגוי!</target>
-<source>Conflict detected:</source>
-<target>התגלה קונפליקט:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>קובץ %x בעל ת×ריך ×–×”×” ×ך גודל שונה!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>קשור סימבולי %x בעל ת×ריך ×–×”×” ×ך מטרה שונה!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>×œ×§×™×©×•×¨×™× ×¡×™×ž×‘×•×œ×™×™× %x יש ת×ריך ×–×”×” ×בל יעד שונה.</target>
<source>Comparing content of files %x</source>
<target>השווה תכולה של ×§×‘×¦×™× %x</target>
@@ -1407,12 +1398,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>יוצר קובץ %x</target>
-<source>Creating folder %x</source>
-<target>יוצר מחיצה %x</target>
-
<source>Creating symbolic link %x</source>
<target>יוצר קישור סימבולי %x</target>
+<source>Creating folder %x</source>
+<target>יוצר מחיצה %x</target>
+
<source>Overwriting file %x</source>
<target>דורס קובץ %x</target>
@@ -1431,8 +1422,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>×œ× ×¡×•×¤×§×” מחיצה ×œ×¨×™×©×•× ×’×¨×¡×ות קבצי×</target>
-<source>Source directory does not exist anymore:</source>
-<target>מחיצת המקור ×œ× × ×ž×¦×ת:</target>
+<source>Source directory %x not found.</source>
+<target>מחיצת מקור %x ×œ× × ×ž×¦××”.</target>
<source>Unresolved conflicts existing!</source>
<target>×§×™×™× ×§×•× ×¤×œ×™×§×˜ ×œ× ×¤×ª×•×¨!</target>
@@ -1467,12 +1458,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>מיצר בסיס נתוני×...</target>
-<source>Nothing to synchronize!</source>
-<target>×ין מה לסנכרן!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>×œ× × ×™×ª×Ÿ להעתיק קובץ נעול %x!</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 12c7ffb7..67b2ac34 100644
--- a/BUILD/Languages/hungarian.lng
+++ b/BUILD/Languages/hungarian.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>Mappa tallózása</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Megszakítási kérelem: Várakozás a folyamatban lévő művelet befejezésére...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatikus szinkronizálás</target>
+<source>Error</source>
+<target>Hiba</target>
+
<source>Select alternate comparison settings</source>
<target>Alternatív összehasonlítás beállításai</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>A programról</target>
-<source>Error</source>
-<target>Hiba</target>
-
<source>Warning</source>
<target>Figyelem</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux hibakód %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>A szimbolikus link feloldása sikertelen:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Sikertelen a következő symlink feloldása: %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bájt</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Hiba történt a szinkronizációs adatbázis olvasása közben:</target>
+<source>Cannot read file %x.</source>
+<target>A következő fájl olvasása sikertelen: %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Hiba történt a szinkronizációs adatbázis írása közben:</target>
+<source>Cannot write file %x.</source>
+<target>A következő fájl írása sikertelen: %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Inkompatibilis szinkronizációs adatbázis formátum:</target>
+<source>Database file %x is incompatible.</source>
+<target>Inkompatibilis adatbázisfájl: %x.</target>
<source>Initial synchronization:</source>
<target>Első szinkronizáció:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>A FreeFileSync egyik adatbázisfájlja nem létezik:</target>
+<source>Database file %x does not yet exist.</source>
+<target>A következő adatbázisfájl nem létezik: %x.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Az adatbázisfájlok nem osztoznak egy közös szinkronizációs munkameneten:</target>
+<source>Out of memory!</source>
+<target>Elfogyott a szabad memória!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Az adatbázisfájlok nem osztanak meg közös munkamenetet.</target>
<source>An exception occurred!</source>
<target>Kivétel keletkezett!</target>
-<source>Error reading file attributes:</source>
-<target>A fájl attribútumainak olvasása sikertelen:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>A következő fájl attribútumainak olvasása sikertelen: %x.</target>
+
+<source>Cannot get process information.</source>
+<target>A processzinformációk lekérdezése sikertelen.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Várakozás a mappa zárolásának a feloldására (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Hiba történt a mappa zárolása közben:</target>
+<source>Cannot set directory lock %x.</source>
+<target>A következő mappa zárolása sikertelen: %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x másodperc</pluralform>
</target>
-<source>Error reading file:</source>
-<target>A fájl olvasása sikertelen:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Hiba történt a fájl feldolgozása közben: %x fájl, %y sor, %z oszlop.</target>
<source>Scanning:</source>
<target>Vizsgálat:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x szál]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Érvénytelen a FreeFileSync beállításait tartalmazó fájl!</target>
+<source>/sec</source>
+<target>/másodperc</target>
-<source>Error parsing configuration file:</source>
-<target>A beállításokat tartalmazó fájl feldolgozása sikertelen:</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>
-<source>Configuration loaded partially only:</source>
-<target>A beállításokat csak részben sikerült betölteni:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Csak részlegesen töltődött be a következő beállításokat tartalmazó fájl: %x.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>%x Lomtárba helyezése sikertelen!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>A Volume Shadow Copy szolgáltatás elérése sikertelen.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Kérjük, használd a FreeFileSync 64 bites verzióját a shadow másolatok készítéséhez ezen a rendszeren.</target>
<source>Cannot load file %x.</source>
<target>%x fájl betöltése sikertelen.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Hiba történt a Volume Shadow Copy szolgáltatás elérése közben!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>A Shadow Copy a WOW64-en nem támogatott. Kérjük, használja a 64-bites FreeFileSync-et.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Nem lehet meghatározni a kötetnevet a következő fájlhoz:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>A következő útvonal nem tartalmaz kötetnevet: %x.</target>
<source>Volume name %x not part of file name %y!</source>
<target>A(z) %x kötetnevet nem tartalmazza a(z) %y fájlnév!</target>
-<source>/sec</source>
-<target>/másodperc</target>
-
-<source>File does not exist:</source>
-<target>A következő fájl nem létezik:</target>
+<source>Cannot find file %x.</source>
+<target>Nem található a következő fájl: %x.</target>
<source>Cannot read the following XML elements:</source>
<target>A következő XML elemek olvasása sikertelen:</target>
@@ -297,15 +300,18 @@ A parancssor végrehajtódik minden alkalommal, ha:
<source>Start</source>
<target>Indítás</target>
+<source>&Retry</source>
+<target>&Ismét</target>
+
+<source>Cancel</source>
+<target>Mégsem</target>
+
<source>(Build: %x)</source>
<target>(Build: %x)</target>
<source>RealtimeSync configuration</source>
<target>RealtimeSync beállítások</target>
-<source>File already exists. Overwrite?</source>
-<target>A fájl már létezik. Felülírjuk?</target>
-
<source>&Restore</source>
<target>&Visszaállítás</target>
@@ -348,35 +354,38 @@ A parancssor végrehajtódik minden alkalommal, ha:
<source>FreeFileSync configuration</source>
<target>FreeFileSync beállítások</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync kötegelt feladat</target>
-
-<source>Unable to create log file!</source>
-<target>Nem lehet létrehozni a naplófájlt!</target>
-
<source>Batch execution</source>
<target>Kötegelt végrehajtás</target>
-<source>Stop</source>
-<target>Megállítás</target>
+<source>Items processed:</source>
+<target>Feldolgozott elemek száma:</target>
+
+<source>Items remaining:</source>
+<target>Hátralévő elemek száma:</target>
<source>Total time:</source>
<target>Becsült idő:</target>
+<source>Stop</source>
+<target>Megállítás</target>
+
<source>Synchronization aborted!</source>
<target>A szinkronizáció megszakítva!</target>
<source>Synchronization completed with errors!</source>
<target>A szinkronizáció befejeződött, de akadtak hibák!</target>
+<source>Nothing to synchronize!</source>
+<target>Nincs mit szinkronizálni!</target>
+
<source>Synchronization completed successfully!</source>
<target>A szinkronizáció sikeresen befejeződött!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Kérjük, nyomja meg a "Váltás" gombot a GUI mód megnyitásához.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Nyomg meg a "Váltás" gombot az események kezeléséhez a FreeFileSync fő párbeszédablakában.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Váltás a FreeFileSync GUI módjára...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Váltás a FreeFileSync fő párbeszédablakára...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>A csatlakozás a sourceforge.net-hez sikertelen!</target>
@@ -534,9 +543,6 @@ A parancssor végrehajtódik minden alkalommal, ha:
<source>Items found:</source>
<target>Talált elemek száma:</target>
-<source>Items remaining:</source>
-<target>Hátralévő elemek száma:</target>
-
<source>Speed:</source>
<target>Sebesség:</target>
@@ -588,9 +594,6 @@ A parancssor végrehajtódik minden alkalommal, ha:
<source>&Load</source>
<target>&Betöltés</target>
-<source>&Cancel</source>
-<target>&Mégsem</target>
-
<source>Select variant:</source>
<target>Változat kiválasztása:</target>
@@ -639,8 +642,8 @@ A parancssor végrehajtódik minden alkalommal, ha:
<source>Conflict/file cannot be categorized</source>
<target>Kategorizálhatatlan ütközések/fájlok</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Összehasonlítás</target>
@@ -673,9 +676,6 @@ A fájlok megegyeznek, ha megegyezik
<source>Synchronizing...</source>
<target>Szinkronizálás folyamatban...</target>
-<source>Items processed:</source>
-<target>Feldolgozott elemek száma:</target>
-
<source>&Pause</source>
<target>&Szünet</target>
@@ -718,9 +718,6 @@ a következő személyeknek:
<source>&Ignore</source>
<target>&Kihagy</target>
-<source>&Retry</source>
-<target>&Ismét</target>
-
<source>Do not show this dialog again</source>
<target>Ne mutasd újra ezt a párbeszédablakot</target>
@@ -1018,9 +1015,6 @@ Kizárni: \stuff\temp\*
<source>File list exported!</source>
<target>A fájllista exportálása befejeződött!</target>
-<source>Error writing file:</source>
-<target>A fájl írása sikertelen:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1066,21 +1060,21 @@ Kizárni: \stuff\temp\*
<source>Paused</source>
<target>Szüneteltetve</target>
+<source>Initializing...</source>
+<target>Inicializálás...</target>
+
<source>Aborted</source>
<target>Megszakítva</target>
<source>Completed</source>
<target>Befejezve</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Megszakítási kérelem: Várakozás a folyamatban lévő művelet befejezésére...</target>
+<source>Continue</source>
+<target>Folytatás</target>
<source>Pause</source>
<target>Szünet</target>
-<source>Continue</source>
-<target>Folytatás</target>
-
<source>Cannot find %x</source>
<target>Nem található: %x</target>
@@ -1219,65 +1213,65 @@ Kizárni: \stuff\temp\*
<pluralform>%x nap</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>A mappafigyelés inicializálása sikertelen:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Hiba történt a mappák figyelése közben.</target>
+<source>Cannot monitor directory %x.</source>
+<target>A következő mappa monitorozása sikertelen: %x.</target>
<source>Conversion error:</source>
<target>Konverziós hiba:</target>
-<source>Error deleting file:</source>
-<target>A fájl törlése sikertelen:</target>
+<source>Cannot delete file %x.</source>
+<target>A következő fájl törlése sikertelen: %x.</target>
-<source>Error moving file:</source>
-<target>Hiba a fájl mozgatásakor:</target>
+<source>The file is locked by another process:</source>
+<target>A fájl zárolva van egy másik processz által:</target>
-<source>Target file already existing!</source>
-<target>A célként megadott fájl már létezik!</target>
+<source>Cannot move file %x to %y.</source>
+<target>%x fájl mozgatása %y fájlba sikertelen.</target>
-<source>Error moving directory:</source>
-<target>Hiba a mappa mozgatásakor:</target>
+<source>Cannot delete directory %x.</source>
+<target>A következő mappa törlése sikertelen: %x.</target>
-<source>Target directory already existing!</source>
-<target>A célmappa már létezik!</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>Error deleting directory:</source>
-<target>A mappa törlése sikertelen:</target>
+<source>Cannot find system function %x.</source>
+<target>Nem található a következő rendszerfunkció: %x.</target>
-<source>Error changing modification time:</source>
-<target>Az utolsó változtatás dátumának módosítása sikertelen:</target>
+<source>Cannot read security context of %x.</source>
+<target>A következő fájl biztonsági tulajdonságainak olvasása sikertelen: %x.</target>
-<source>Error loading library function:</source>
-<target>A könyvtári funkció betöltése sikertelen:</target>
+<source>Cannot write security context of %x.</source>
+<target>A következő fájl biztonsági tulajdonságainak írása sikertelen: %x.</target>
-<source>Error reading security context:</source>
-<target>A biztonsági címke olvasása sikertelen:</target>
+<source>Cannot read permissions of %x.</source>
+<target>A következő fájl jogosultságainak az olvasása sikertelen: %x.</target>
-<source>Error writing security context:</source>
-<target>A biztonsági címke írása sikertelen:</target>
+<source>Cannot write permissions of %x.</source>
+<target>A következő fájl jogosultságainak az írása sikertelen: %x.</target>
-<source>Error copying file permissions:</source>
-<target>Hiba történt a fájl jogosultságainak másolása közben:</target>
+<source>Cannot create directory %x.</source>
+<target>A következő mappa létrehozása sikertelen: %x.</target>
-<source>Error creating directory:</source>
-<target>A mappa létrehozása sikertelen:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>%x symlink másolása a(z) %y symlinkbe sikertelen.</target>
-<source>Error copying symbolic link:</source>
-<target>Hiba történt a szimbolikus link másolása közben:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>A következő fájl attribútumainak írása sikertelen: %x.</target>
-<source>Error copying file:</source>
-<target>A fájl másolása sikertelen:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>%x fájl másolása a(z) %y fájlba sikertelen.</target>
-<source>Error traversing directory:</source>
-<target>A mappa átnézése sikertelen:</target>
+<source>Cannot read directory %x.</source>
+<target>A következő mappa olvasása sikertelen: %x.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Végtelen hurok a mappák bejárásakor:</target>
+<source>Endless loop.</source>
+<target>Végtelen hurok.</target>
-<source>Error setting privilege:</source>
-<target>Hiba történt a jogok beállítása közben:</target>
+<source>Cannot set privilege %x.</source>
+<target>A következő privilégium beállítása sikertelen: %x.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>%x Lomtárba helyezése sikertelen!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Mindkét oldal megváltozott az utolsó szikronizálás óta!</target>
@@ -1303,8 +1297,8 @@ Kizárni: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Figyelmen kívül hagyhatod ezt a hibát, üresnek tekintve a mappát.</target>
-<source>Directory does not exist:</source>
-<target>A mappa nem létezik:</target>
+<source>Cannot find directory %x.</source>
+<target>Nem található a következő mappa: %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>A mappák függenek egymástól! Legyen óvatos, amikor megadja a szinkronizálási szabályokat:</target>
@@ -1312,20 +1306,17 @@ Kizárni: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Szinkronizálás előkészítése...</target>
-<source>Out of memory!</source>
-<target>Elfogyott a szabad memória!</target>
+<source>Conflict detected:</source>
+<target>Ütközés történt:</target>
<source>File %x has an invalid date!</source>
<target>A(z) %x fájlnak érvénytelen a dátuma!</target>
-<source>Conflict detected:</source>
-<target>Ütközés történt:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>A(z) %x fájlok dátuma megegyezik, de a mérete nem!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>A(z) %x symlinknek megegyezik a dátuma, de a célpontja nem!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>A következő symlinkeknek megegyezik a dátuma, de a célpontjuk különböző: %x.</target>
<source>Comparing content of files %x</source>
<target>%x fájlok tartalmának összehasonlítása</target>
@@ -1408,12 +1399,12 @@ Kizárni: \stuff\temp\*
<source>Creating file %x</source>
<target>%x fájl létrehozása</target>
-<source>Creating folder %x</source>
-<target>%x mappa létrehozása</target>
-
<source>Creating symbolic link %x</source>
<target>%x symlink létrehozása</target>
+<source>Creating folder %x</source>
+<target>%x mappa létrehozása</target>
+
<source>Overwriting file %x</source>
<target>%x fájl felülírása</target>
@@ -1432,8 +1423,8 @@ Kizárni: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Nem lett megadva mappa a fájlok verziókezeléséhez!</target>
-<source>Source directory does not exist anymore:</source>
-<target>A forrásként megadott mappa többé nem létezik:</target>
+<source>Source directory %x not found.</source>
+<target>Nem található a következő forrásmappa: %x.</target>
<source>Unresolved conflicts existing!</source>
<target>Feloldatlan ütközések vannak!</target>
@@ -1468,12 +1459,6 @@ Kizárni: \stuff\temp\*
<source>Generating database...</source>
<target>Adatbázis generálása...</target>
-<source>Nothing to synchronize!</source>
-<target>Nincs mit szinkronizálni!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>A zárolt %x fájl másolása sikertelen!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Adatellenőrzési hiba: A forrás és cél fájl tartalma különbözik!</target>
diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng
index 1ba11fea..27523f4d 100644
--- a/BUILD/Languages/italian.lng
+++ b/BUILD/Languages/italian.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>Sfoglia cartelle</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Selezionata interruazione: conclusione dell'operazione...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Sincronizzazione automatizzata</target>
+<source>Error</source>
+<target>Errore</target>
+
<source>Select alternate comparison settings</source>
<target>Seleziona impostazioni di comparazione alternative</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>Info su</target>
-<source>Error</source>
-<target>Errore</target>
-
<source>Warning</source>
<target>Attenzione</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux - Errore codice %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Errore nella risoluzione di collegamento simbolico:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target></target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Byte</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Errore in lettura dal database di sincronizzione:</target>
+<source>Cannot read file %x.</source>
+<target>Impossibile leggere il file %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Errore in scrittura sul database di sincronizzazione:</target>
+<source>Cannot write file %x.</source>
+<target>Impossibile scrivere il file %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Formato database di sincronizzazione incompatibile:</target>
+<source>Database file %x is incompatible.</source>
+<target>Il file database %x non è compatibile.</target>
<source>Initial synchronization:</source>
<target>Prima sincronizzazione:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Un file database di FreeFileSync non è ancora stato creato:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Il file database %x non è ancora stato creato.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>I file database non condividono una comune sessione di sincronizzazione:</target>
+<source>Out of memory!</source>
+<target>Memoria insufficiente!</target>
+
+<source>Database files do not share a common session.</source>
+<target>I file database non condividono una sessione comune.</target>
<source>An exception occurred!</source>
-<target>Si è verificato una ececzione!</target>
+<target>Si è verificata una eccezione!</target>
+
+<source>Cannot read file attributes of %x.</source>
+<target>Impossibile leggere gli attributi del file %x.</target>
-<source>Error reading file attributes:</source>
-<target>Errore di lettura degli attributi file:</target>
+<source>Cannot get process information.</source>
+<target>Impossibile ottenere informazioni sul processo.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Attendi mentre la cartella è bloccata (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Errore nell'impostazione del blocco cartella:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Impossibile impostare il blocco cartella %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sec</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Errore durante la lettura del file:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Errore nel parsing del file %x, riga %y, colonna %z.</target>
<source>Scanning:</source>
<target>Analisi di:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>File di configurazione FreeFileSync non valido!</target>
+<source>/sec</source>
+<target>/sec</target>
-<source>Error parsing configuration file:</source>
-<target>Errore nell'analisi del file di configurazione:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>Il file %x non contiene una configurazione valida.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configurazione caricata solo parzialmente:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>File di configurazione %x caricato solo parzialmente.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Impossibile spostare %x nel Cestino!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Impossibile accedere al servizio Volume Shadow Copy.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>E' necessario utilizzare FreeFileSync versione 64-bit per creare copie shadow su questo sistema.</target>
<source>Cannot load file %x.</source>
<target>Impossibile caricare il file %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Errore in accesso al servizio Volume Shadow Copy</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>La creazione di copie shadow su WOW64 non e' supportata. Utilizzare FreeFileSync in versione 64 bit.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Impossibile determinare il nome volume per il il file:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Il percorso %x non contiene un nome di volume.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Il nome volume %x non è parte del nome file %y!</target>
-<source>/sec</source>
-<target>/sec</target>
-
-<source>File does not exist:</source>
-<target>Il file non esiste:</target>
+<source>Cannot find file %x.</source>
+<target>Impossibile trovare il file %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Impossibile leggere i seguenti elementi XML:</target>
@@ -297,15 +300,18 @@ La linea di comando è eseguita ogni volta che:
<source>Start</source>
<target>Avvia</target>
+<source>&Retry</source>
+<target>&Riprova</target>
+
+<source>Cancel</source>
+<target>Annulla</target>
+
<source>(Build: %x)</source>
<target>(Versione: %x)</target>
<source>RealtimeSync configuration</source>
<target>Configurazione di RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Il file esiste già. Lo vuoi sovrascrivere?</target>
-
<source>&Restore</source>
<target>&Ripristina</target>
@@ -348,35 +354,38 @@ La linea di comando è eseguita ogni volta che:
<source>FreeFileSync configuration</source>
<target>Configurazione di FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync job attività</target>
-
-<source>Unable to create log file!</source>
-<target>Impossibile creare il file del registro attività!</target>
-
<source>Batch execution</source>
<target>Esecuzione in batch</target>
-<source>Stop</source>
-<target>Stop</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>Synchronization aborted!</source>
<target>Sincronizzazione abortita!</target>
<source>Synchronization completed with errors!</source>
<target>Sincronizzazione completata con errori!</target>
+<source>Nothing to synchronize!</source>
+<target>Non c'è nulla da sincronizzare!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sincronizzazione completata con successo!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Premi "Switch" per aprire modalità GUI di FreeFileSync</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Premere "Passa" per risolvere i problemi nella finestra principale di FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Switch alla modalità GUI di FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Sto passando alla finestra principale di FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Impossibile collegarsi a sourceforge.net!</target>
@@ -534,9 +543,6 @@ La linea di comando è eseguita ogni volta che:
<source>Items found:</source>
<target>Elementi trovati:</target>
-<source>Items remaining:</source>
-<target>Elementi rimanenti:</target>
-
<source>Speed:</source>
<target>Velocita':</target>
@@ -588,9 +594,6 @@ La linea di comando è eseguita ogni volta che:
<source>&Load</source>
<target>&Carica</target>
-<source>&Cancel</source>
-<target>&Annulla</target>
-
<source>Select variant:</source>
<target>Seleziona una variante:</target>
@@ -639,8 +642,8 @@ La linea di comando è eseguita ogni volta che:
<source>Conflict/file cannot be categorized</source>
<target>I conflitti/file non possono essere categorizzati</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Compara per...</target>
@@ -675,9 +678,6 @@ I file sono considerati identici se
<source>Synchronizing...</source>
<target>Sincronizzazione...</target>
-<source>Items processed:</source>
-<target>Elementi processati:</target>
-
<source>&Pause</source>
<target>&Pausa</target>
@@ -717,14 +717,11 @@ I file sono considerati identici se
<source>&Ignore</source>
<target>&Ignora</target>
-<source>&Retry</source>
-<target>&Riprova</target>
-
<source>Do not show this dialog again</source>
<target>Non visualizzare più questo messaggio</target>
<source>&Switch</source>
-<target>&Switch</target>
+<target>&Passa</target>
<source>&Yes</source>
<target>&Si</target>
@@ -1017,9 +1014,6 @@ Escludi: \stuff\temp\*
<source>File list exported!</source>
<target>Elenco file esportato!</target>
-<source>Error writing file:</source>
-<target>Errore durante la scrittura del file:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Escludi: \stuff\temp\*
<source>Paused</source>
<target>In pausa</target>
+<source>Initializing...</source>
+<target>Inizializzazione...</target>
+
<source>Aborted</source>
<target>Interrotto</target>
<source>Completed</source>
<target>Completato</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Selezionata interruazione: conclusione dell'operazione...</target>
+<source>Continue</source>
+<target>Continua</target>
<source>Pause</source>
<target>Pausa</target>
-<source>Continue</source>
-<target>Continua</target>
-
<source>Cannot find %x</source>
<target>Impossibile trovare %x</target>
@@ -1218,65 +1212,65 @@ Escludi: \stuff\temp\*
<pluralform>%x giorni</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Monitoraggio cartella non inizializzabile:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Errore durante il monitoraggio cartella.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Impossibile monitorare la cartella %x.</target>
<source>Conversion error:</source>
<target>Errore di conversione:</target>
-<source>Error deleting file:</source>
-<target>Errore durante l'eliminazione del file:</target>
+<source>Cannot delete file %x.</source>
+<target>Impossibile eliminare il file %x.</target>
-<source>Error moving file:</source>
-<target>Errore nello spostamento file:</target>
+<source>The file is locked by another process:</source>
+<target>Il file è bloccato da un altro processo:</target>
-<source>Target file already existing!</source>
-<target>File destinazione già esistente!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Impossibile spostare il file %x in %y.</target>
-<source>Error moving directory:</source>
-<target>Errore nello spostamento directory:</target>
+<source>Cannot delete directory %x.</source>
+<target>Impossibile eliminare la cartella %x.</target>
-<source>Target directory already existing!</source>
-<target>Cartella di destinazione già esistente!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Impossibile scrivere data e ora di modifica di %x.</target>
-<source>Error deleting directory:</source>
-<target>Errore durante l'eliminazione delle cartella:</target>
+<source>Cannot find system function %x.</source>
+<target>Impossibile trovare funzione di sistema %x.</target>
-<source>Error changing modification time:</source>
-<target>Errore durante la modifica della data:</target>
+<source>Cannot read security context of %x.</source>
+<target>Impossibile leggere il contesto di protezione di %x.</target>
-<source>Error loading library function:</source>
-<target>Errore nel caricamento della funzione libreria:</target>
+<source>Cannot write security context of %x.</source>
+<target>Impossibile scrivere il contesto di protezione di %x.</target>
-<source>Error reading security context:</source>
-<target>Errore in lettura del contesto di sicurezza:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Impossibile leggere i permessi di %x.</target>
-<source>Error writing security context:</source>
-<target>Errore in scrittura del contesto di sicurezza:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Impossibile scrivere i permessi di %x.</target>
-<source>Error copying file permissions:</source>
-<target>Errore durante la copia dei permessi su file:</target>
+<source>Cannot create directory %x.</source>
+<target>Impossibile creare cartella %x.</target>
-<source>Error creating directory:</source>
-<target>Errore durante la creazione della cartella:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Impossibile copiare collegamento simbolico %x su %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Errore durante la copia del link simbolico:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Impossibile scrivere attributi file di %x.</target>
-<source>Error copying file:</source>
-<target>Errore durante la copia del file:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Impossibile copiare file %x in %y.</target>
-<source>Error traversing directory:</source>
-<target>Errore nello spostamento cartella:</target>
+<source>Cannot read directory %x.</source>
+<target>Impossibile leggere cartella %x.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Loop senza fine nello spostamento cartella:</target>
+<source>Endless loop.</source>
+<target>Loop senza fine.</target>
-<source>Error setting privilege:</source>
-<target>Errore nell'impostazione dei privilegi:</target>
+<source>Cannot set privilege %x.</source>
+<target>Impossibile impostare privilegi %x.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Impossibile spostare %x nel Cestino!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Entrambi i lati sono cambiati dall'ultima sincronizzazione!</target>
@@ -1302,8 +1296,8 @@ Escludi: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Puoi ignorare questo errore per considerare la cartella come vuota.</target>
-<source>Directory does not exist:</source>
-<target>La cartella non esiste:</target>
+<source>Cannot find directory %x.</source>
+<target>Impossibile trovare cartella %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Le cartelle sono dipendenti! Fai attenzione quando configuri le regole di sincronizzazione:</target>
@@ -1311,20 +1305,17 @@ Escludi: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Preparazione sincronizzazione...</target>
-<source>Out of memory!</source>
-<target>Memoria insufficiente!</target>
+<source>Conflict detected:</source>
+<target>Rilevato conflitto:</target>
<source>File %x has an invalid date!</source>
<target>Il file %x ha una data non valida!</target>
-<source>Conflict detected:</source>
-<target>Rilevato conflitto:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>I file %x hanno la stessa data ma dimensione diversa!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>I link simbolici %x hanno stessa data ma differente target!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Collegamento simbolico %x ha stessa data ma un diverso puntamento.</target>
<source>Comparing content of files %x</source>
<target>Comparazione contenuto del file %x</target>
@@ -1407,12 +1398,12 @@ Escludi: \stuff\temp\*
<source>Creating file %x</source>
<target>Creazione file %x</target>
-<source>Creating folder %x</source>
-<target>Creazione cartella %x</target>
-
<source>Creating symbolic link %x</source>
<target>Creazione link simbolico %x</target>
+<source>Creating folder %x</source>
+<target>Creazione cartella %x</target>
+
<source>Overwriting file %x</source>
<target>Sovrascrittura file %x</target>
@@ -1431,8 +1422,8 @@ Escludi: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Non è stata indicata una cartella per il file delle versioni!</target>
-<source>Source directory does not exist anymore:</source>
-<target>La cartella sorgente non esiste più:</target>
+<source>Source directory %x not found.</source>
+<target>Cartella sorgente %x non trovata.</target>
<source>Unresolved conflicts existing!</source>
<target>Sono presenti conflitti irrisolti!</target>
@@ -1467,12 +1458,6 @@ Escludi: \stuff\temp\*
<source>Generating database...</source>
<target>Generazione database...</target>
-<source>Nothing to synchronize!</source>
-<target>Non c'è nulla da sincronizzare!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Impossibile copiare il file bloccato %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Errore nella verifica data: i file sorgente e destinazione hanno differente contenuto!</target>
diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng
index 9f04e478..1d7b1b65 100644
--- a/BUILD/Languages/japanese.lng
+++ b/BUILD/Languages/japanese.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>ディレクトリをå‚ç…§</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>ユーザã«ã‚ˆã‚‹ä¸­æ–­: ç¾åœ¨ã®å‡¦ç†ã‚’終了ã—ã¦ã„ã¾ã™.. ãŠå¾…ã¡ãã ã•ã„...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>リアルタイムåŒæœŸ - 自動åŒæœŸ</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux エラーコード %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>シンボリックリンクã®è§£æ±ºã«å¤±æ•—:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>シンボリックリンク %x を解決ã§ãã¾ã›ã‚“.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -135,35 +138,41 @@
<pluralform>%x ãƒã‚¤ãƒˆ</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‹ã‚‰ã®èª­ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot read file %x.</source>
+<target>ファイル %x を読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error writing to synchronization database:</source>
-<target>åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸ã®æ›¸ãè¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot write file %x.</source>
+<target>ファイル %x ã«æ›¸ãè¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Incompatible synchronization database format:</source>
-<target>åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ›¸å¼ã«äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“:</target>
+<source>Database file %x is incompatible.</source>
+<target>データベース %x ã¨ã¯äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“.</target>
<source>Initial synchronization:</source>
<target>åŒæœŸå‡¦ç†ã®åˆæœŸåŒ–:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>FreeFileSync データベースファイルãŒå­˜åœ¨ã—ã¾ã›ã‚“:</target>
+<source>Database file %x does not yet exist.</source>
+<target>データベース %x ã¯å­˜åœ¨ã—ã¾ã›ã‚“.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>データベースファイルã¯ä¸€èˆ¬çš„ãªåŒæœŸã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’共有ã—ã¾ã›ã‚“:</target>
+<source>Out of memory!</source>
+<target>メモリãŒè¶³ã‚Šã¾ã›ã‚“!</target>
+
+<source>Database files do not share a common session.</source>
+<target>データベースã¯ä¸€èˆ¬ã‚»ãƒƒã‚·ãƒ§ãƒ³ã§å…±æœ‰ã§ãã¾ã›ã‚“.</target>
<source>An exception occurred!</source>
<target>例外ãŒç™ºç”Ÿã—ã¾ã—ãŸ!</target>
-<source>Error reading file attributes:</source>
-<target>ファイル属性ã®å–å¾—ã«å¤±æ•—:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>%x ã®ãƒ•ã‚¡ã‚¤ãƒ«å±žæ€§ã‚’読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
+
+<source>Cannot get process information.</source>
+<target>プロセス情報をå–å¾—ã§ãã¾ã›ã‚“.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>待機時間中ディレクトリã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¾ã™(%x)...</target>
-<source>Error setting directory lock:</source>
-<target>ディレクトリ設定ã«å¤±æ•—(ロック):</target>
+<source>Cannot set directory lock %x.</source>
+<target>%x ã®ãƒ­ãƒƒã‚¯ã‚’セットã§ãã¾ã›ã‚“.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -173,8 +182,8 @@
<pluralform>%x 秒.</pluralform>
</target>
-<source>Error reading file:</source>
-<target>ファイル読ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>ファイル %x ã®æ§‹æ–‡è§£æžã‚¨ãƒ©ãƒ¼, è¡Œ %y, 列 %z.</target>
<source>Scanning:</source>
<target>スキャン:</target>
@@ -190,38 +199,32 @@
<pluralform>[%x スレッド]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>無効㪠FreeFileSync 構æˆãƒ•ã‚¡ã‚¤ãƒ«ã§ã™!</target>
+<source>/sec</source>
+<target>/秒</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>ファイル %x ã«ã¯æœ‰åŠ¹ãªæ§‹æˆãŒå«ã¾ã‚Œã¦ã„ã¾ã›ã‚“.</target>
-<source>Error parsing configuration file:</source>
-<target>構æˆãƒ•ã‚¡ã‚¤ãƒ«ã®æ§‹æ–‡ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>構æˆãƒ•ã‚¡ã‚¤ãƒ« %x ã¯éƒ¨åˆ†çš„ã®ã¿èª­ã¿è¾¼ã¾ã‚Œã¾ã™.</target>
-<source>Configuration loaded partially only:</source>
-<target>部分的ã®ã¿èª­ã¿è¾¼ã¾ã‚ŒãŸæ§‹æˆ:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>ボリュームシャドウコピーサービスã«ã‚¢ã‚¯ã‚»ã‚¹å‡ºæ¥ã¾ã›ã‚“.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>%x をゴミ箱ã«ç§»å‹•ã§ãã¾ã›ã‚“!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>FreeFileSync 64-bit 版を使用ã—ã¦ã“ã®ã‚·ã‚¹ãƒ†ãƒ ã«ã‚·ãƒ£ãƒ‰ã‚¦ã‚³ãƒ”ーを作æˆã—ã¦ãã ã•ã„.</target>
<source>Cannot load file %x.</source>
<target>ファイル %x を読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>ボリュームシャドウ・コピーサービスã«ã‚¢ã‚¯ã‚»ã‚¹å‡ºæ¥ã¾ã›ã‚“!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>WOW64 ã§ã¯ã€ãƒœãƒªãƒ¥ãƒ¼ãƒ ã‚·ãƒ£ãƒ‰ã‚¦ã‚³ãƒ”ーã«å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“ã€FreeFileSync 64-bit 版をãŠè©¦ã—ãã ã•ã„。</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>ファイルã®ãƒœãƒªãƒ¥ãƒ¼ãƒ åを解決出æ¥ã¾ã›ã‚“:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>パス %x ã«ã¯ãƒœãƒªãƒ¥ãƒ¼ãƒ åãŒå«ã¾ã‚Œã¦ã„ã¾ã›ã‚“.</target>
<source>Volume name %x not part of file name %y!</source>
<target>ボリュームå %x ã«ãƒ•ã‚¡ã‚¤ãƒ«å %y ã¯ã‚ã‚Šã¾ã›ã‚“!</target>
-<source>/sec</source>
-<target>/秒</target>
-
-<source>File does not exist:</source>
-<target>ファイルãŒå­˜åœ¨ã—ã¾ã›ã‚“:</target>
+<source>Cannot find file %x.</source>
+<target>ファイル %x ãŒã¿ã¤ã‹ã‚Šã¾ã›ã‚“.</target>
<source>Cannot read the following XML elements:</source>
<target>次㮠XMLè¦ç´ ã‚’読ã¿è¾¼ã‚ã¾ã›ã‚“:</target>
@@ -300,9 +303,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>リアルタイムåŒæœŸã®æ§‹æˆè¨­å®š</target>
-<source>File already exists. Overwrite?</source>
-<target>ファイルã¯å­˜åœ¨ã—ã¾ã™ã€ä¸Šæ›¸ãã—ã¾ã™ã‹?</target>
-
<source>&Restore</source>
<target>修復(&R)</target>
@@ -345,35 +345,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>FreeFileSync 構æˆè¨­å®š</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync 一括ジョブ</target>
-
-<source>Unable to create log file!</source>
-<target>ログファイルを作æˆå‡ºæ¥ã¾ã›ã‚“!</target>
-
<source>Batch execution</source>
<target>一括処ç†ã‚’実行</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>åŒæœŸå‡¦ç†ã‚’中断!</target>
<source>Synchronization completed with errors!</source>
<target>åŒæœŸå‡¦ç†ã¯ã€ã‚¨ãƒ©ãƒ¼ã§çµ‚了ã—ã¦ã„ã¾ã™!</target>
+<source>Nothing to synchronize!</source>
+<target>åŒæœŸå¯¾è±¡ãŒã‚ã‚Šã¾ã›ã‚“!</target>
+
<source>Synchronization completed successfully!</source>
<target>åŒæœŸå‡¦ç†ã¯ã™ã¹ã¦æ­£å¸¸ã«å®Œäº†ã—ã¾ã—ãŸ!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>"切り替ãˆ" を押ã™ã¨ FreeFileSync GUI モードã§é–‹ãã¾ã™</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>"切り替ãˆ"を押ã™ã¨ FreeFileSync ダイアログã®å•é¡Œã‚’解決ã—ã¾ã™.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>FreeFileSync GUI モードã®åˆ‡ã‚Šæ›¿ãˆä¸­...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>FreeFileSync メインダイアログを切替中...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Sourceforge.net ã«æŽ¥ç¶šã§ãã¾ã›ã‚“!</target>
@@ -531,9 +534,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>見ã¤ã‹ã£ãŸè¦ç´ :</target>
-<source>Items remaining:</source>
-<target>残りã®è¦ç´ :</target>
-
<source>Speed:</source>
<target>速度:</target>
@@ -561,9 +561,6 @@ The command line is executed each time:
<source>Right</source>
<target>å³å´</target>
-<source>Sync setttings</source>
-<target>åŒæœŸè¨­å®š</target>
-
<source>Status feedback</source>
<target>状態 フィードãƒãƒƒã‚¯</target>
@@ -588,8 +585,8 @@ The command line is executed each time:
<source>&Load</source>
<target>読ã¿è¾¼ã¿(&L)</target>
-<source>&Cancel</source>
-<target>キャンセル(&C)</target>
+<source>Cancel</source>
+<target>キャンセル</target>
<source>Select variant:</source>
<target>変数をé¸æŠž:</target>
@@ -639,8 +636,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>競åˆãŒã‚ã‚‹ãŸã‚分類ã§ãã¾ã›ã‚“</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>比較対象...</target>
@@ -675,9 +672,6 @@ is the same
<source>Synchronizing...</source>
<target>åŒæœŸå‡¦ç†ä¸­...</target>
-<source>Items processed:</source>
-<target>処ç†ã•ã‚ŒãŸè¦ç´ :</target>
-
<source>&Pause</source>
<target>一時åœæ­¢(&P)</target>
@@ -1017,9 +1011,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>ファイル一覧ã®ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãŒå®Œäº†!</target>
-<source>Error writing file:</source>
-<target>ファイル書ãè¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1061,21 +1052,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>一時åœæ­¢ä¸­</target>
+<source>Initializing...</source>
+<target>åˆæœŸåŒ–中...</target>
+
<source>Aborted</source>
<target>中断</target>
<source>Completed</source>
<target>完了ã—ã¾ã—ãŸ</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>ユーザã«ã‚ˆã‚‹ä¸­æ–­: ç¾åœ¨ã®å‡¦ç†ã‚’終了ã—ã¦ã„ã¾ã™.. ãŠå¾…ã¡ãã ã•ã„...</target>
+<source>Continue</source>
+<target>続行</target>
<source>Pause</source>
<target>一時åœæ­¢</target>
-<source>Continue</source>
-<target>続行</target>
-
<source>Cannot find %x</source>
<target>%x ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“</target>
@@ -1209,68 +1200,65 @@ Exclude: \stuff\temp\*
<pluralform>%x æ—¥</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>監視ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’åˆæœŸåŒ–ã§ãã¾ã›ã‚“:</target>
-
-<source>Error when monitoring directories.</source>
-<target>ディレクトリã®ç›£è¦–エラー</target>
+<source>Cannot monitor directory %x.</source>
+<target>ディレクトリ %x を監視ã§ãã¾ã›ã‚“.</target>
<source>Conversion error:</source>
<target>変æ›ã‚¨ãƒ©ãƒ¼:</target>
-<source>Error deleting file:</source>
-<target>ファイルã®å‰Šé™¤ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot delete file %x.</source>
+<target>ファイル %x を削除出æ¥ã¾ã›ã‚“.</target>
-<source>Error moving file:</source>
-<target>ファイルã®ç§»å‹•ã«å¤±æ•—:</target>
+<source>The file is locked by another process:</source>
+<target>次ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯åˆ¥ã®ãƒ—ロセスã§ä½¿ç”¨ä¸­ã§ã™:</target>
-<source>Target file already existing!</source>
-<target>対象ファイルã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™!</target>
+<source>Cannot move file %x to %y.</source>
+<target>ファイル %x ã‚’ %y ã«ç§»å‹•ã§ãã¾ã›ã‚“.</target>
-<source>Error moving directory:</source>
-<target>ディレクトリ移動ã«å¤±æ•—:</target>
+<source>Cannot delete directory %x.</source>
+<target>ディレクトリ %x を削除ã§ãã¾ã›ã‚“.</target>
-<source>Target directory already existing!</source>
-<target>対象ディレクトリã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™!</target>
+<source>Cannot write modification time of %x.</source>
+<target>%x ã®æ›´æ–°æ™‚刻を書ãè¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ.</target>
-<source>Error deleting directory:</source>
-<target>ディレクトリã®å‰Šé™¤ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot find system function %x.</source>
+<target>システム関数 %x ãŒã¿ã¤ã‹ã‚Šã¾ã›ã‚“.</target>
-<source>Error changing modification time:</source>
-<target>時間ã®ä¿®æ­£ä¸­ã®ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot read security context of %x.</source>
+<target>%x ã®ï½¾ï½·ï½­ï¾˜ï¾ƒï½¨ï½ºï¾ï¾ƒï½·ï½½ï¾„を読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error loading library function:</source>
-<target>ライブラリ読ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot write security context of %x.</source>
+<target>>%x ã®ï½¾ï½·ï½­ï¾˜ï¾ƒï½¨ï½ºï¾ï¾ƒï½·ï½½ï¾„を書ãè¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error reading security context:</source>
-<target>セキュリティ・コンテキストã®èª­ã¿å–りエラー:</target>
+<source>Cannot read permissions of %x.</source>
+<target>>%x ã®ï¾Šï¾Ÿï½°ï¾ï½¯ï½¼ï½®ï¾ã‚’読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error writing security context:</source>
-<target>セキュリティ・コンテキストã®æ›¸ãè¾¼ã¿ã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot write permissions of %x.</source>
+<target>%x ã®ï¾Šï¾Ÿï½°ï¾ï½¯ï½¼ï½®ï¾ã‚’書ãè¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error copying file permissions:</source>
-<target>パーミッションコピー中ã®ã‚¨ãƒ©ãƒ¼</target>
+<source>Cannot create directory %x.</source>
+<target>ディレクトリ %x を作æˆå‡ºæ¥ã¾ã›ã‚“.</target>
-<source>Error creating directory:</source>
-<target>ディレクトリ作æˆã‚¨ãƒ©ãƒ¼:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>S リンクを %x ã‹ã‚‰ %y ã«ã‚³ãƒ”ーã§ãã¾ã›ã‚“.</target>
-<source>Error copying symbolic link:</source>
-<target>シンボリックリンクã®ã‚³ãƒ”ーã«å¤±æ•—:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%x ã®ãƒ•ã‚¡ã‚¤ãƒ«å±žæ€§ã‚’書ãè¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error copying file:</source>
-<target>ファイルã®ã‚³ãƒ”ーã«å¤±æ•—:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>%x ã‹ã‚‰ %y ã«ã‚³ãƒ”ーã§ãã¾ã›ã‚“.</target>
-<source>Error opening file:</source>
-<target>ファイルã®ã‚ªãƒ¼ãƒ—ンã«å¤±æ•—:</target>
+<source>Cannot read directory %x.</source>
+<target>ディレクトリ %x を読ã¿è¾¼ã‚ã¾ã›ã‚“.</target>
-<source>Error traversing directory:</source>
-<target>ディレクトリã®ç§»å‹•ã‚¨ãƒ©ãƒ¼:</target>
+<source>Endless loop.</source>
+<target>エンドレスループ</target>
-<source>Endless loop when traversing directory:</source>
-<target>ディレクトリ移動中ã«ç„¡é™ãƒ«ãƒ¼ãƒ—ãŒç™ºç”Ÿ:</target>
+<source>Cannot set privilege %x.</source>
+<target>%x ã®ç‰¹æ¨©ã‚’セットã§ãã¾ã›ã‚“.</target>
-<source>Error setting privilege:</source>
-<target>特権ã®è¨­å®šã‚¨ãƒ©ãƒ¼:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>%x をゴミ箱ã«ç§»å‹•ã§ãã¾ã›ã‚“!</target>
<source>Both sides have changed since last synchronization!</source>
<target>å‰å›žæœ€å¾Œã®åŒæœŸå‡¦ç†ä»¥é™ã€ä¸¡å´ã¨ã‚‚変更ãŒã‚ã‚Šã¾ã™!</target>
@@ -1296,8 +1284,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>ディレクトリãŒç©ºã¨è€ƒæ…®ã™ã‚‹å ´åˆã€ã“ã®ã‚¨ãƒ©ãƒ¼ã¯ç„¡è¦–ã§ãã¾ã™ã€‚</target>
-<source>Directory does not exist:</source>
-<target>ディレクトリãŒå­˜åœ¨ã—ã¾ã›ã‚“:</target>
+<source>Cannot find directory %x.</source>
+<target>ディレクトリ %x ãŒã¿ã¤ã‹ã‚Šã¾ã›ã‚“.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>ディレクトリãŒä¾å­˜é–¢ä¿‚ã«ã‚ã‚Šã¾ã™! åŒæœŸè¦å‰‡ã®è¨­å®šæ™‚ã«ã¯æ³¨æ„ã—ã¦ãã ã•ã„:</target>
@@ -1305,20 +1293,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>åŒæœŸå‡¦ç†ã®æº–備中...</target>
-<source>Out of memory!</source>
-<target>メモリãŒè¶³ã‚Šã¾ã›ã‚“!</target>
+<source>Conflict detected:</source>
+<target>検出ã•ã‚ŒãŸç«¶åˆ:</target>
<source>File %x has an invalid date!</source>
<target>ファイル %x ã®æ—¥ä»˜ã¯ç„¡åŠ¹ãªã‚‚ã®ã§ã™!</target>
-<source>Conflict detected:</source>
-<target>検出ã•ã‚ŒãŸç«¶åˆ:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>ファイル %x ã¯ã€åŒã˜æ™‚é–“ã§ã™ãŒã‚µã‚¤ã‚ºãŒç•°ãªã£ã¦ã„ã¾ã™!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>シンボリックリンク %x ã®æ—¥ä»˜ã¯åŒä¸€ã§ã™ãŒã€ç•°ãªã‚‹å¯¾è±¡ãŒã‚ã‚Šã¾ã™!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>シンボリックリンク %x ã®æ—¥ä»˜ã¯åŒã˜ã§ã™ãŒã€å¯¾è±¡ãŒç•°ãªã£ã¦ã„ã¾ã™.</target>
<source>Comparing content of files %x</source>
<target>ファイル %x ã®å†…容を比較中</target>
@@ -1401,12 +1386,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>ファイル %x を作æˆä¸­</target>
-<source>Creating folder %x</source>
-<target>フォルダ %x を作æˆä¸­</target>
-
<source>Creating symbolic link %x</source>
<target>シンボリックリンク %x を作æˆä¸­</target>
+<source>Creating folder %x</source>
+<target>フォルダ %x を作æˆä¸­</target>
+
<source>Overwriting file %x</source>
<target>ファイル %x を上書ã中</target>
@@ -1425,8 +1410,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>ファイルãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒåˆ©ç”¨ã§ããªã„ディレクトリã§ã™!</target>
-<source>Source directory does not exist anymore:</source>
-<target>ソースディレクトリãŒå­˜åœ¨ã—ã¾ã›ã‚“:</target>
+<source>Source directory %x not found.</source>
+<target>ソースディレクトリ %x ãŒã¿ã¤ã‹ã‚Šã¾ã›ã‚“.</target>
<source>Unresolved conflicts existing!</source>
<target>未解決ã®ä¸ä¸€è‡´ãŒã‚ã‚Šã¾ã™!</target>
@@ -1461,12 +1446,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>データベースを作æˆä¸­...</target>
-<source>Nothing to synchronize!</source>
-<target>åŒæœŸå¯¾è±¡ãŒã‚ã‚Šã¾ã›ã‚“!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>ファイル %x ã¯ã‚³ãƒ”ーã§ãã¾ã›ã‚“!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>データ検証エラー: ソースã¨å¯¾è±¡ãƒ•ã‚¡ã‚¤ãƒ«ã«ç•°ãªã‚‹å†…容ãŒå«ã¾ã‚Œã¦ã„ã¾ã™!</target>
diff --git a/BUILD/Languages/korean.lng b/BUILD/Languages/korean.lng
index 36a10add..b7952f45 100644
--- a/BUILD/Languages/korean.lng
+++ b/BUILD/Languages/korean.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>디렉토리 찾아보기</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>사용ìžì— ì˜í•œ ìž‘ì—… 중단 : 현재 ìž‘ì—… 종료 대기 중...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>실시간 ë™ê¸°í™” - ìžë™ ë™ê¸°í™”</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>리눅스 ì—러 코드 %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>심볼릭 ë§í¬ë¥¼ í•´ê²°í•˜ë˜ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>심볼릭 ë§í¬ %x ì„(를) í•´ê²°í•  수 없습니다.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -135,35 +138,41 @@
<pluralform>%x ë°”ì´íŠ¸</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>ë™ê¸°í™” ë°ì´í„°ë² ì´ìŠ¤ë¡œë¶€í„° ì½ì–´ 들ì´ë˜ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot read file %x.</source>
+<target>íŒŒì¼ %x ì„(를) ì½ì„ 수 없습니다.</target>
-<source>Error writing to synchronization database:</source>
-<target>ë™ê¸°í™” ë°ì´í„°ë² ì´ìŠ¤ì— ì“°ë˜ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Cannot write file %x.</source>
+<target>íŒŒì¼ %x ì„(를) 쓸 수 없습니다.</target>
-<source>Incompatible synchronization database format:</source>
-<target>호환ë˜ì§€ 않는 ë™ê¸°í™” ë°ì´í„°ë² ì´ìŠ¤ í˜•ì‹ :</target>
+<source>Database file %x is incompatible.</source>
+<target>ë°ì´í„°ë² ì´ìŠ¤ íŒŒì¼ %x ì€(는) 호환 불가능합니다.</target>
<source>Initial synchronization:</source>
<target>초기 ë™ê¸°í™” :</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>FreeFileSync ë°ì´í„°ë² ì´ìŠ¤ íŒŒì¼ ì¤‘ 하나가 ì•„ì§ ì¡´ìž¬í•˜ì§€ 않습니다 :</target>
+<source>Database file %x does not yet exist.</source>
+<target>ë°ì´í„°ë² ì´ìŠ¤ íŒŒì¼ %x ì€(는) ì•„ì§ ì¡´ìž¬í•˜ì§€ 않습니다.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>ë°ì´í„°ë² ì´ìŠ¤ 파ì¼ì´ 공통 ë™ê¸°í™” ì„¸ì…˜ì„ ê³µìœ í•˜ì§€ 않습니다 :</target>
+<source>Out of memory!</source>
+<target>메모리 부족!</target>
+
+<source>Database files do not share a common session.</source>
+<target>ë°ì´í„°ë² ì´ìŠ¤ 파ì¼ì´ ì¼ë°˜/ê³µë™ ì„¸ì…˜ì„ ê³µìœ í•˜ì§€ 않습니다.</target>
<source>An exception occurred!</source>
<target>예외 ë°œìƒ!</target>
-<source>Error reading file attributes:</source>
-<target>íŒŒì¼ ì†ì„±ì„ ì½ë˜ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot read file attributes of %x.</source>
+<target>%xì˜ íŒŒì¼ ì†ì„±ì„ ì½ì„ 수 없습니다.</target>
+
+<source>Cannot get process information.</source>
+<target>프로세스 정보를 ì–»ì„ ìˆ˜ 없습니다.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>디렉토리 잠금 대기 중 (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>디렉토리 잠금 설정 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot set directory lock %x.</source>
+<target>디렉토리 잠금 %x ì„(를) 설정할 수 없습니다.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -173,8 +182,8 @@
<pluralform>%xì´ˆ</pluralform>
</target>
-<source>Error reading file:</source>
-<target>파ì¼ì„ ì½ë˜ 중 ë°œìƒí•œ 오류 :</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>ë¶„ì„ ì˜¤ë¥˜ - 파ì¼: %x, í–‰: %y, ì—´: %z</target>
<source>Scanning:</source>
<target>스캔 :</target>
@@ -190,38 +199,32 @@
<pluralform>[%x 스레드]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>ìž˜ëª»ëœ FreeFileSync 설정 파ì¼!</target>
+<source>/sec</source>
+<target>/ì´ˆ</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>íŒŒì¼ %x ì˜ êµ¬ì„±ì´ ìœ íš¨í•˜ì§€ 않습니다.</target>
-<source>Error parsing configuration file:</source>
-<target>ì„¤ì •íŒŒì¼ ë¶„ì„ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>구성 íŒŒì¼ %x ì´(ê°€) 부분ì ìœ¼ë¡œë§Œ 로드 ë˜ì—ˆìŒ.</target>
-<source>Configuration loaded partially only:</source>
-<target>êµ¬ì„±ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ 로드 ë습니다 :</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Volume Shadow Copy Service 접근 불가</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>%x ì„(를) 휴지통으로 ì´ë™í•  수 없습니다!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>본 ìš´ì˜ì²´ì œì—ì„œì˜ Shadow Copy ìƒì„±ì€ FreeFileSync 64-비트 ë²„ì „ì„ ì‚¬ìš©í•˜ì„¸ìš”.</target>
<source>Cannot load file %x.</source>
<target>íŒŒì¼ %x ì„(를) 로드할 수 없습니다.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>볼륨 ì„€ë„ ë³µì‚¬ë³¸ ì„œë¹„ìŠ¤ì— ì•¡ì„¸ìŠ¤í•˜ë˜ ì¤‘ 오류 ë°œìƒ!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>WOW64 ì—ì„œì˜ Shadow Copy 는 지ì›í•˜ì§€ 않습니다. FreeFileSync 64-bit ë²„ì „ì„ ì‚¬ìš©í•˜ì„¸ìš”.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>파ì¼ì˜ 볼륨 ì´ë¦„ì„ ê²°ì •í•  수 없습니다 :</target>
+<source>Path %x does not contain a volume name.</source>
+<target>경로 %xì— ë³¼ë¥¨ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤.</target>
<source>Volume name %x not part of file name %y!</source>
-<target>볼륨 ì´ë¦„ %x ì´(ê°€) íŒŒì¼ ì´ë¦„ %y ì˜ ì¼ë¶€ê°€ 아닙니다!</target>
+<target>볼륨 ì´ë¦„ %x ì€(는) íŒŒì¼ ì´ë¦„ %y ì˜ ì¼ë¶€ê°€ 아님!</target>
-<source>/sec</source>
-<target>/ì´ˆ</target>
-
-<source>File does not exist:</source>
-<target>파ì¼ì´ 존재하지 않습니다 :</target>
+<source>Cannot find file %x.</source>
+<target>íŒŒì¼ %x ì„(를) ì°¾ì„ ìˆ˜ 없습니다.</target>
<source>Cannot read the following XML elements:</source>
<target>ë‹¤ìŒ XML 요소를 ì½ì„ 수 없습니다 :</target>
@@ -300,9 +303,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>실시간 ë™ê¸°í™” 설정</target>
-<source>File already exists. Overwrite?</source>
-<target>파ì¼ì´ ì´ë¯¸ 존재합니다. ë®ì–´ 쓰시겠습니까?</target>
-
<source>&Restore</source>
<target>ë³µì›(&R)</target>
@@ -345,35 +345,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>FreeFileSync 구성 설정</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync ì¼ê´„ ìž‘ì—…</target>
-
-<source>Unable to create log file!</source>
-<target>ë¡œê·¸íŒŒì¼ ìƒì„±ì„ í•  수 없습니다!</target>
-
<source>Batch execution</source>
<target>ì¼ê´„ 실행</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>ë™ê¸°í™” 중단!</target>
<source>Synchronization completed with errors!</source>
<target>ë™ê¸°í™”ê°€ 완료ë˜ê¸´ 했으나, 오류가 있습니다!</target>
+<source>Nothing to synchronize!</source>
+<target>ë™ê¸°í™” í•  í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤!</target>
+
<source>Synchronization completed successfully!</source>
<target>ë™ê¸°í™”ê°€ 성공ì ìœ¼ë¡œ 완료 ë습니다!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>FreeFileSync GUI 모드는 "전환" ì„ ëˆ„ë¥´ë©´ 열립니다.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>FreeFileSync ë©”ì¸ ë‹¤ì´ì–¼ë¡œê·¸ì—ì„œ 문제 í•´ê²°ì„ í•˜ë ¤ë©´ "Switch" [전환]ì„ ëˆ„ë¥´ì‹­ì‹œì˜¤.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>FreeFileSync GUI 모드로 전환 중...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>FreeFileSync ë©”ì¸ ë‹¤ì´ì–¼ë¡œê·¸ë¡œ 전환 중...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Sourceforge.netì— ì ‘ì†í•  수 없습니다!</target>
@@ -531,9 +534,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>ë°œê²¬ëœ í•­ëª© :</target>
-<source>Items remaining:</source>
-<target>ë‚¨ì€ í•­ëª© :</target>
-
<source>Speed:</source>
<target>ì†ë„ :</target>
@@ -561,9 +561,6 @@ The command line is executed each time:
<source>Right</source>
<target>우측</target>
-<source>Sync setttings</source>
-<target>싱í¬(ë™ê¸°í™”) 설정</target>
-
<source>Status feedback</source>
<target>ìƒíƒœ 피드백</target>
@@ -588,8 +585,8 @@ The command line is executed each time:
<source>&Load</source>
<target>로드(&L)</target>
-<source>&Cancel</source>
-<target>취소(&C)</target>
+<source>Cancel</source>
+<target>취소</target>
<source>Select variant:</source>
<target>옵션 ì„ íƒ :</target>
@@ -639,8 +636,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>충ëŒ/íŒŒì¼ ë¶„ë¥˜ 불가능</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>ëŒ€ìƒ ë³„ 비êµ...</target>
@@ -675,9 +672,6 @@ is the same
<source>Synchronizing...</source>
<target>ë™ê¸°í™” ìž‘ì—… 중...</target>
-<source>Items processed:</source>
-<target>ì²˜ë¦¬ëœ í•­ëª© :</target>
-
<source>&Pause</source>
<target>ì¼ì‹œì •ì§€(&P)</target>
@@ -808,7 +802,7 @@ Exclude: \stuff\temp\*
<target>ë½ ê±¸ë¦° íŒŒì¼ ë³µì‚¬</target>
<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
-<target>Volume Shadow Copy를 사용하여 공유 ë˜ëŠ” ë½ ê±¸ë¦° 파ì¼ì„ 복사 (ê´€ë¦¬ìž ê¶Œí•œ í•„ìš”)</target>
+<target>Volume Shadow Copy Service를 사용하여 공유 ë˜ëŠ” ë½ ê±¸ë¦° 파ì¼ì„ 복사 (ê´€ë¦¬ìž ê¶Œí•œ í•„ìš”)</target>
<source>Copy file access permissions</source>
<target>íŒŒì¼ ì ‘ê·¼ 권한 복사</target>
@@ -1017,9 +1011,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>íŒŒì¼ ë¦¬ìŠ¤íŠ¸ 내보내기 완료!</target>
-<source>Error writing file:</source>
-<target>파ì¼ì„ ì“°ë˜ ì¤‘ ë°œìƒí•œ 오류 :</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1061,21 +1052,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>ì¼ì‹œì •ì§€ 중</target>
+<source>Initializing...</source>
+<target>초기화 작업 중...</target>
+
<source>Aborted</source>
<target>중단ë¨</target>
<source>Completed</source>
<target>완료</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>사용ìžì— ì˜í•œ ìž‘ì—… 중단 : 현재 ìž‘ì—… 종료 대기 중...</target>
+<source>Continue</source>
+<target>계ì†</target>
<source>Pause</source>
<target>ì¼ì‹œì •ì§€</target>
-<source>Continue</source>
-<target>계ì†</target>
-
<source>Cannot find %x</source>
<target>%x ì„(를) ì°¾ì„ ìˆ˜ 없습니다.</target>
@@ -1174,7 +1165,7 @@ Exclude: \stuff\temp\*
<target>파ì¼</target>
<source>Percentage</source>
-<target>í¼ì„¼í‹°ì§€(백분율)</target>
+<target>백분율(%)</target>
<source>%x TB</source>
<target>%x TB</target>
@@ -1209,68 +1200,65 @@ Exclude: \stuff\temp\*
<pluralform>%xì¼</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>디렉토리 모니터ë§ì„ 초기화 í•  수 없습니다 :</target>
-
-<source>Error when monitoring directories.</source>
-<target>디렉토리 ëª¨ë‹ˆí„°ë§ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Cannot monitor directory %x.</source>
+<target>디렉토리 %x ì„(를) ëª¨ë‹ˆí„°ë§ í•  수 없습니다.</target>
<source>Conversion error:</source>
<target>변환 오류 :</target>
-<source>Error deleting file:</source>
-<target>íŒŒì¼ ì‚­ì œ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot delete file %x.</source>
+<target>íŒŒì¼ %x ì„(를) 삭제할 수 없습니다.</target>
-<source>Error moving file:</source>
-<target>íŒŒì¼ ì´ë™ 중 ë°œìƒí•œ 오류 :</target>
+<source>The file is locked by another process:</source>
+<target>파ì¼ì´ 다른 í”„ë¡œì„¸ìŠ¤ì— ì˜í•´ 잠겨 있습니다 :</target>
-<source>Target file already existing!</source>
-<target>ëŒ€ìƒ íŒŒì¼ì´ ì´ë¯¸ 존재합니다!</target>
+<source>Cannot move file %x to %y.</source>
+<target>íŒŒì¼ %x ì„(를) %y (으)ë¡œ ì´ë™í•  수 없습니다.</target>
-<source>Error moving directory:</source>
-<target>디렉토리 ì´ë™ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot delete directory %x.</source>
+<target>디렉토리 %x ì„(를) 삭제할 수 없습니다.</target>
-<source>Target directory already existing!</source>
-<target>ëŒ€ìƒ ë””ë ‰í† ë¦¬ê°€ ì´ë¯¸ 존재합니다!</target>
+<source>Cannot write modification time of %x.</source>
+<target>%xì˜ ìˆ˜ì • ì‹œê°„ì„ ì“¸ 수 없습니다.</target>
-<source>Error deleting directory:</source>
-<target>디렉토리 ì‚­ì œ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot find system function %x.</source>
+<target>시스템 함수 %x ì„(를) ì°¾ì„ ìˆ˜ 없습니다.</target>
-<source>Error changing modification time:</source>
-<target>시간 수정 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot read security context of %x.</source>
+<target>%xì˜ ë³´ì•ˆ 컨í…스트를 ì½ì„ 수 없습니다.</target>
-<source>Error loading library function:</source>
-<target>ë¼ì´ë¸ŒëŸ¬ë¦¬ 기능 로드 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot write security context of %x.</source>
+<target>%xì˜ ë³´ì•ˆ 컨í…스트를 쓸 수 없습니다.</target>
-<source>Error reading security context:</source>
-<target>보안 컨í…스트를 ì½ë˜ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot read permissions of %x.</source>
+<target>%xì˜ ê¶Œí•œì„ ì½ì„ 수 없습니다.</target>
-<source>Error writing security context:</source>
-<target>보안 컨í…스트를 ì“°ë˜ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Cannot write permissions of %x.</source>
+<target>%xì˜ ê¶Œí•œì„ ì“¸ 수 없습니다.</target>
-<source>Error copying file permissions:</source>
-<target>íŒŒì¼ ê¶Œí•œ 복사 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot create directory %x.</source>
+<target>디렉토리 %x ì„(를) ìƒì„±í•  수 없습니다.</target>
-<source>Error creating directory:</source>
-<target>디렉토리 ìƒì„± 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>심볼릭 ë§í¬ %x ì„(를) %y (으)ë¡œ 복사할 수 없습니다.</target>
-<source>Error copying symbolic link:</source>
-<target>심볼릭 ë§í¬ 복사 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%xì˜ íŒŒì¼ ì†ì„±ì„ 쓸 수 없습니다.</target>
-<source>Error copying file:</source>
-<target>íŒŒì¼ ë³µì‚¬ 중 ë°œìƒí•œ 오류 :</target>
+<source>Cannot copy file %x to %y.</source>
+<target>íŒŒì¼ %x ì„(를) %y (으)ë¡œ 복사할 수 없습니다.</target>
-<source>Error opening file:</source>
-<target>파ì¼ì„ ì—´ë˜ ì¤‘ ë°œìƒí•œ 오류 :</target>
+<source>Cannot read directory %x.</source>
+<target>디렉토리 %x ì„(를) ì½ì„ 수 없습니다.</target>
-<source>Error traversing directory:</source>
-<target>디렉토리 ì´ë™ 중 ë°œìƒí•œ 오류 :</target>
+<source>Endless loop.</source>
+<target>무한 루프</target>
-<source>Endless loop when traversing directory:</source>
-<target>디렉토리 ì´ë™ 중 무한 루프 ë°œìƒ :</target>
+<source>Cannot set privilege %x.</source>
+<target>권한 %x ì„(를) 설정할 수 없습니다.</target>
-<source>Error setting privilege:</source>
-<target>권한 설정 중 ë°œìƒí•œ 오류 :</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>%x ì„(를) 휴지통으로 ì´ë™í•  수 없습니다!</target>
<source>Both sides have changed since last synchronization!</source>
<target>마지막 ë™ê¸°í™” ìž‘ì—… ì´í›„, 양측 ëª¨ë‘ ë³€ê²½ ë˜ì—ˆìŠµë‹ˆë‹¤!</target>
@@ -1296,8 +1284,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>디렉토리가 비었다는 오류는 무시 가능합니다.</target>
-<source>Directory does not exist:</source>
-<target>디렉토리가 존재하지 않습니다 :</target>
+<source>Cannot find directory %x.</source>
+<target>디렉토리 %x ì„(를) ì°¾ì„ ìˆ˜ 없습니다.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>디렉토리가 ì˜ì¡´ ê´€ê³„ì— ìžˆìŠµë‹ˆë‹¤. ë™ê¸°í™” 규칙 설정시 주ì˜í•˜ì‹­ì‹œì˜¤.</target>
@@ -1305,20 +1293,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>ë™ê¸°í™” 준비 중...</target>
-<source>Out of memory!</source>
-<target>메모리 부족!</target>
+<source>Conflict detected:</source>
+<target>íƒì§€ëœ 충ëŒ/불ì¼ì¹˜ :</target>
<source>File %x has an invalid date!</source>
<target>íŒŒì¼ %x ì˜ ë‚ ì§œê°€ 유효하지 않습니다!</target>
-<source>Conflict detected:</source>
-<target>íƒì§€ëœ 충ëŒ/불ì¼ì¹˜ :</target>
-
<source>Files %x have the same date but a different size!</source>
<target>íŒŒì¼ %x ì˜ ë‚ ì§œëŠ” 같으나, í¬ê¸°ê°€ 다릅니다!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>심ë§í¬ %x ì˜ ë‚ ì§œëŠ” 같으나, 대ìƒì´ 다릅니다!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>심볼릭 ë§í¬ %x ì˜ ë‚ ì§œëŠ” 같으나, íƒ€ê²Ÿì´ ë‹¤ë¦…ë‹ˆë‹¤.</target>
<source>Comparing content of files %x</source>
<target>íŒŒì¼ %x ë‚´ìš© 별 ë¹„êµ ì¤‘</target>
@@ -1381,32 +1366,32 @@ Exclude: \stuff\temp\*
<target>심볼릭 ë§í¬ %x ì‚­ì œ 중</target>
<source>Moving file %x to recycle bin</source>
-<target>íŒŒì¼ %x를(ì„) 휴지통으로 ì´ë™ 중</target>
+<target>íŒŒì¼ %xì„(를) 휴지통으로 ì´ë™ 중</target>
<source>Moving folder %x to recycle bin</source>
-<target>í´ë” %x를(ì„) 휴지통으로 ì´ë™ 중</target>
+<target>í´ë” %xì„(를) 휴지통으로 ì´ë™ 중</target>
<source>Moving symbolic link %x to recycle bin</source>
-<target>심볼릭 ë§í¬ %x를(ì„) 휴지통으로 ì´ë™ 중</target>
+<target>심볼릭 ë§í¬ %xì„(를) 휴지통으로 ì´ë™ 중</target>
<source>Moving file %x to %y</source>
-<target>íŒŒì¼ %x를(ì„) %y(으)ë¡œ ì´ë™ 중</target>
+<target>íŒŒì¼ %xì„(를) %y(으)ë¡œ ì´ë™ 중</target>
<source>Moving folder %x to %y</source>
-<target>í´ë” %x를(ì„) %y(으)ë¡œ ì´ë™ 중</target>
+<target>í´ë” %xì„(를) %y(으)ë¡œ ì´ë™ 중</target>
<source>Moving symbolic link %x to %y</source>
-<target>심볼릭 ë§í¬ %x를(ì„) %y(으)ë¡œ ì´ë™ 중</target>
+<target>심볼릭 ë§í¬ %xì„(를) %y(으)ë¡œ ì´ë™ 중</target>
<source>Creating file %x</source>
<target>íŒŒì¼ %x ìƒì„± 중</target>
-<source>Creating folder %x</source>
-<target>í´ë” %x ìƒì„± 중</target>
-
<source>Creating symbolic link %x</source>
<target>심볼릭 ë§í¬ %x ìƒì„± 중</target>
+<source>Creating folder %x</source>
+<target>í´ë” %x ìƒì„± 중</target>
+
<source>Overwriting file %x</source>
<target>íŒŒì¼ %x ë®ì–´ì“°ëŠ” 중</target>
@@ -1425,8 +1410,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>íŒŒì¼ ë²„ì €ë‹ì„ 위한 디렉토리가 제공ë˜ì§€ 않았습니다!</target>
-<source>Source directory does not exist anymore:</source>
-<target>소스 디렉토리가 ë” ì´ìƒ 존재하지 않습니다 :</target>
+<source>Source directory %x not found.</source>
+<target>소스 디렉토리 %x ì„(를) ì°¾ì„ ìˆ˜ 없습니다.</target>
<source>Unresolved conflicts existing!</source>
<target>í•´ê²°ë˜ì§€ ì•Šì€ ì¶©ëŒì´ 있습니다!</target>
@@ -1461,12 +1446,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>ë°ì´í„°ë² ì´ìŠ¤ ìƒì„± 중...</target>
-<source>Nothing to synchronize!</source>
-<target>ë™ê¸°í™” í•  í•­ëª©ì´ ì—†ìŠµë‹ˆë‹¤!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>잠겨진 íŒŒì¼ %x ì„(를) 복사할 수 없습니다!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>ë°ì´í„° í™•ì¸ ì˜¤ë¥˜ : 소스 ë° íƒ€ê²Ÿ 파ì¼ì˜ ë‚´ìš©ì´ ë‹¤ë¦…ë‹ˆë‹¤!</target>
diff --git a/BUILD/Languages/lithuanian.lng b/BUILD/Languages/lithuanian.lng
new file mode 100644
index 00000000..9506c48c
--- /dev/null
+++ b/BUILD/Languages/lithuanian.lng
@@ -0,0 +1,1487 @@
+<header>
+ <language name>Lietuvių</language name>
+ <translator>Liudas Ališauskas</translator>
+ <locale>lt_LT</locale>
+ <flag file>lithuania.png</flag file>
+ <plural forms>4</plural forms>
+ <plural definition>n==1 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3</plural definition>
+</header>
+
+<source>Searching for directory %x...</source>
+<target>IÅ¡koma aplanko %x...</target>
+
+<source>Show in Explorer</source>
+<target>Rodyti naršyklėje</target>
+
+<source>Open with default application</source>
+<target>Atverti su numatyta programa</target>
+
+<source>Browse directory</source>
+<target>Naršyti aplanką</target>
+
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Nutraukti: laukiama kol baigsis esama operacija...</target>
+
+<source>RealtimeSync - Automated Synchronization</source>
+<target>RealtimeSync - Automatizuotas sinchronizavimas</target>
+
+<source>Error</source>
+<target>Klaida</target>
+
+<source>Select alternate comparison settings</source>
+<target>Pasirinkite alternatyvius sulyginimo nustatymus</target>
+
+<source>Select alternate synchronization settings</source>
+<target>Pasirinkite alternatyvius sinchronizavimo nustatymus</target>
+
+<source>No filter selected</source>
+<target>Nepažymėti jokie filtrai</target>
+
+<source>Filter is active</source>
+<target>Filtas yra aktyvus</target>
+
+<source>Remove alternate settings</source>
+<target>Pašalinti alternatyvius nustatymus</target>
+
+<source>Clear filter settings</source>
+<target>IÅ¡valyti filtro nustatymus</target>
+
+<source>Create a batch job</source>
+<target>Sukurti paketinę užduotį</target>
+
+<source>Synchronization settings</source>
+<target>Sinchronizavimo nustatymai</target>
+
+<source>Comparison settings</source>
+<target>Sulyginimo nustatymai</target>
+
+<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>
+
+<source>Configure filter</source>
+<target>Nustatyti filtrÄ…</target>
+
+<source>Global settings</source>
+<target>Bendri nustatymai</target>
+
+<source>Synchronization Preview</source>
+<target>Sinchronizavimo peržiūra</target>
+
+<source>Find</source>
+<target>Rasti</target>
+
+<source>Select time span</source>
+<target>Pažymėti laiko trukmę</target>
+
+<source>Show pop-up</source>
+<target>Rodyti pranešimą</target>
+
+<source>Show pop-up on errors or warnings</source>
+<target>Rodyti pranešimą esant klaidoms ar perspėjimams</target>
+
+<source>Ignore errors</source>
+<target>Ignoruoti klaidas</target>
+
+<source>Hide all error and warning messages</source>
+<target>Slėpti visus klaidų ir perspėjimų pranešimus</target>
+
+<source>Exit instantly</source>
+<target>Išeiti iškart</target>
+
+<source>Abort synchronization immediately</source>
+<target>Atšaukti sinchronizavimą dabar</target>
+
+<source>Browse</source>
+<target>Naršyti</target>
+
+<source>Invalid command line: %x</source>
+<target>Netinkama komandinÄ— eilutÄ—: %x</target>
+
+<source>Info</source>
+<target>Informacija</target>
+
+<source>Fatal Error</source>
+<target>KritinÄ— klaida</target>
+
+<source>Windows Error Code %x:</source>
+<target>Windows klaidos kodas %x:</target>
+
+<source>Linux Error Code %x:</source>
+<target>Linux klaidos kodas %x:</target>
+
+<source>Cannot resolve symbolic link %x.</source>
+<target>Nepavyksta išspręsti simbolinės nuorodos.</target>
+
+<source>%x MB</source>
+<target>%x MB</target>
+
+<source>%x KB</source>
+<target>%x KB</target>
+
+<source>%x GB</source>
+<target>%x GB</target>
+
+<source>
+<pluralform>1 Byte</pluralform>
+<pluralform>%x Bytes</pluralform>
+</source>
+<target>
+<pluralform>1 Baitas</pluralform>
+<pluralform>%x Baitai</pluralform>
+<pluralform>%x Baitų</pluralform>
+<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>
+
+<source>Initial synchronization:</source>
+<target>Pirminis sinchronizavimas:</target>
+
+<source>Database file %x does not yet exist.</source>
+<target>Duomenų bazės failo %x dar nėra.</target>
+
+<source>Out of memory!</source>
+<target>Trūksta atminties!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Duomenų bazės failai nesidalina bendros sesijos.</target>
+
+<source>An exception occurred!</source>
+<target>Atsirado išimtis!</target>
+
+<source>Cannot read file attributes of %x.</source>
+<target>Nepavyksta nuskaityti failo atributų</target>
+
+<source>Cannot get process information.</source>
+<target>Nepavyksta gauti eigos informacijos.</target>
+
+<source>Waiting while directory is locked (%x)...</source>
+<target>Laikiama kol aplankas bus užrakintas (%x)...</target>
+
+<source>Cannot set directory lock %x.</source>
+<target>Nepavyksta nustatyti aplanko užrakto %x.</target>
+
+<source>
+<pluralform>1 sec</pluralform>
+<pluralform>%x sec</pluralform>
+</source>
+<target>
+<pluralform>1 sek</pluralform>
+<pluralform>%x sek</pluralform>
+<pluralform>%x sek</pluralform>
+<pluralform>%x sek</pluralform>
+</target>
+
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Klaida trinant failÄ… %x, eilÄ— %y, stulpelis %z.</target>
+
+<source>Scanning:</source>
+<target>Skenuojama:</target>
+
+<source>Encoding extended time information: %x</source>
+<target>Koduojama išplėstinė laiko informacija: %x</target>
+
+<source>
+<pluralform>[1 Thread]</pluralform>
+<pluralform>[%x Threads]</pluralform>
+</source>
+<target>
+<pluralform>[1 GrÄ—smÄ—]</pluralform>
+<pluralform>[%x GrÄ—smÄ—s]</pluralform>
+<pluralform>[%x Grėsmių]</pluralform>
+<pluralform>[%x GrÄ—smÄ—s]</pluralform>
+</target>
+
+<source>/sec</source>
+<target>/sek.</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Failas %x neturi tinkamų nustatymų.</target>
+
+<source>Configuration file %x loaded partially only.</source>
+<target>Nustatymų failas %x įkeltas tik dalinai.</target>
+
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Nepavyksta apsiekti tomo Å¡Ä—Å¡Ä—linio kopijavimo tarnybos.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Prašome naudoti 64-bit FreeFileSync versiją, kad sukurti šėšėlines kopijas šioje sistemoje.</target>
+
+<source>Cannot load file %x.</source>
+<target>Nepavyksta įkelti failo %x.</target>
+
+<source>Path %x does not contain a volume name.</source>
+<target>Kelias %x neturi tomo pavadinimo.</target>
+
+<source>Volume name %x not part of file name %y!</source>
+<target>Tomo pavadinimas %x nÄ—ra dalis failo pavadinimo %y!</target>
+
+<source>Cannot find file %x.</source>
+<target>Nepavyksta rasti failo %x.</target>
+
+<source>Cannot read the following XML elements:</source>
+<target>Nepavyksta perskaityti sekanÄių XML elementų:</target>
+
+<source>S&ave configuration...</source>
+<target>IÅ¡s&augoti nustatymus...</target>
+
+<source>&Load configuration...</source>
+<target>Įke&lti nustatymus...</target>
+
+<source>&Quit</source>
+<target>&IÅ¡eiti</target>
+
+<source>&File</source>
+<target>&Failas</target>
+
+<source>&Content</source>
+<target>&Turinys</target>
+
+<source>&About...</source>
+<target>&Apie...</target>
+
+<source>&Help</source>
+<target>&Pagalba</target>
+
+<source>Usage:</source>
+<target>Naudojimas:</target>
+
+<source>1. Select directories to monitor.</source>
+<target>1. Pažymėti aplankus stebėjimui.</target>
+
+<source>2. Enter a command line.</source>
+<target>2. Įvesti komandinę eilutę.</target>
+
+<source>3. Press 'Start'.</source>
+<target>3. Spauskite „Pradėti“'.</target>
+
+<source>
+The command line is executed each time:
+- all directories become available (e.g. USB stick insert)
+- files within these directories or subdirectories are modified
+</source>
+<target>
+Komandinė eilutė yra įvykdoma kas kart:
+- visi aplankai tampa pasiekiamais (pvz. USB atmintukas įkišamas)
+- failai Å¡iuose aplankuose ar poaplankiuose yra pakeisti
+</target>
+
+<source>Directories to watch</source>
+<target>Aplankai stebÄ—jimui</target>
+
+<source>Add folder</source>
+<target>PridÄ—ti aplankÄ…</target>
+
+<source>Remove folder</source>
+<target>Pašalinti aplanką</target>
+
+<source>Select a folder</source>
+<target>Pažymėti aplanką</target>
+
+<source>Command line</source>
+<target>KomandinÄ— eilutÄ—</target>
+
+<source>Minimum Idle Time [seconds]</source>
+<target>Mažiausias neveikimo laikas [sekundės]</target>
+
+<source>Idle time between detection of last change and execution of command line in seconds</source>
+<target>Neveikimo laikas tarp paskutinio pakeitimo nustatymo ir komandinės eilutės įvykdymo sekundėmis</target>
+
+<source>Start</source>
+<target>PradÄ—ti</target>
+
+<source>&Retry</source>
+<target>&Bandyti vÄ—l</target>
+
+<source>Cancel</source>
+<target>Atšaukti</target>
+
+<source>(Build: %x)</source>
+<target>(Komponavimo versija: %x)</target>
+
+<source>RealtimeSync configuration</source>
+<target>RealtimeSync nustatymai</target>
+
+<source>&Restore</source>
+<target>&Atstatyti</target>
+
+<source>&Exit</source>
+<target>&IÅ¡eiti</target>
+
+<source>Monitoring active...</source>
+<target>StebÄ—jimas aktyvus...</target>
+
+<source>Waiting for missing directories...</source>
+<target>Laikiama trūkstamų aplankų...</target>
+
+<source>A directory input field is empty.</source>
+<target>Aplanko įvedimo laukelis yra tuÅ¡Äias.</target>
+
+<source>Logging</source>
+<target>Užduoties duomenys</target>
+
+<source>File time and size</source>
+<target>Failo laiką ir dydį</target>
+
+<source>File content</source>
+<target>Failo turinį</target>
+
+<source><Automatic></source>
+<target><Automatiškai></target>
+
+<source>Mirror ->></source>
+<target>Veidrodis ->></target>
+
+<source>Update -></source>
+<target>Atnaujinti -></target>
+
+<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>Batch execution</source>
+<target>Paketinės užduoties vykdymas</target>
+
+<source>Items processed:</source>
+<target>Elementų apdorota:</target>
+
+<source>Items remaining:</source>
+<target>LikÄ™ elementai:</target>
+
+<source>Total time:</source>
+<target>Visas laikas:</target>
+
+<source>Stop</source>
+<target>Stabdyti</target>
+
+<source>Synchronization aborted!</source>
+<target>Synchronizavimas nutrauktas!</target>
+
+<source>Synchronization completed with errors!</source>
+<target>Synchronizavimas baigtas su klaidomis!</target>
+
+<source>Nothing to synchronize!</source>
+<target>NÄ—ra ko sinchronizuoti!</target>
+
+<source>Synchronization completed successfully!</source>
+<target>Synchronizavimas baigtas sÄ—kmingai!</target>
+
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Spauskite „Perjungti“, kad išspręsti problemas pagrindiniame FreeFileSync lange.</target>
+
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Perjungiama į pagrindinį FreeFileSync langą...</target>
+
+<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>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>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>
+
+<source>(Requires an Internet connection!)</source>
+<target>(Reikalingas interneto ryšys!)</target>
+
+<source><Symlink></source>
+<target><SimbolinÄ— nuoroda></target>
+
+<source><Directory></source>
+<target><Aplankas></target>
+
+<source>Full path</source>
+<target>Pilnas kelias</target>
+
+<source>Name</source>
+<target>Pavadinimas</target>
+
+<source>Relative path</source>
+<target>Atitinkamas kelias</target>
+
+<source>Directory</source>
+<target>Aplankas</target>
+
+<source>Size</source>
+<target>Dydis</target>
+
+<source>Date</source>
+<target>Data</target>
+
+<source>Extension</source>
+<target>PlÄ—tinys</target>
+
+<source>Comparison Result</source>
+<target>Sulyginimo rezultatas</target>
+
+<source>Drag && drop</source>
+<target>Vilkti ir numesti</target>
+
+<source>Close progress dialog</source>
+<target>Uždaryti eigos langą</target>
+
+<source>Shut down</source>
+<target>Išjungti kompiuterį</target>
+
+<source>Log off</source>
+<target>Atsijungti</target>
+
+<source>Standby</source>
+<target>Stabdyti į diską</target>
+
+<source>Hibernate</source>
+<target>Stabdyti į operatyviąją atmintį</target>
+
+<source>1. &Compare</source>
+<target>1. &Sulyginti</target>
+
+<source>2. &Synchronize...</source>
+<target>2. &Sinchronizuoti...</target>
+
+<source>&New</source>
+<target>&Naujas</target>
+
+<source>&Program</source>
+<target>&Programa</target>
+
+<source>&Language</source>
+<target>&Kalba</target>
+
+<source>&Global settings...</source>
+<target>&Bendri nustatymai...</target>
+
+<source>&Create batch job...</source>
+<target>&Sukurti paketinę užduotį...</target>
+
+<source>&Export file list...</source>
+<target>&Eksportuoti failų sąrašą...</target>
+
+<source>&Advanced</source>
+<target>&IÅ¡samiau</target>
+
+<source>&Check for new version</source>
+<target>&Tikrinti dėl atnaujinimų</target>
+
+<source>Compare</source>
+<target>Sulyginti</target>
+
+<source>Compare both sides</source>
+<target>Sulyginti abi puses</target>
+
+<source>&Abort</source>
+<target>&Nutraukti</target>
+
+<source>Synchronize...</source>
+<target>Sinchronizuoti...</target>
+
+<source>Start synchronization</source>
+<target>PradÄ—ti sinchronizavimÄ…</target>
+
+<source>Add folder pair</source>
+<target>Pridėti aplankų porą</target>
+
+<source>Remove folder pair</source>
+<target>Pašalinti aplankų porą</target>
+
+<source>Swap sides</source>
+<target>Sukeisti puses</target>
+
+<source>Save current configuration to file</source>
+<target>Išsaugoti esamus nustatymus į failą</target>
+
+<source>Load configuration from file</source>
+<target>Įkelti nustatymus iš failo</target>
+
+<source>Last used configurations (press DEL to remove from list)</source>
+<target>Paskiausiai naudoti nustatymai (spauskite DEL, kad pašalinti iš sąrašo)</target>
+
+<source>Hide excluded items</source>
+<target>Slėpti neįtrauktus elementus</target>
+
+<source>Hide filtered or temporarily excluded files</source>
+<target>Slėpti išfiltruotus ar laikinai neįtrauktus failus</target>
+
+<source>Number of files and directories that will be created</source>
+<target>SkaiÄius failų ir aplankų, kurie bus sukurti</target>
+
+<source>Number of files that will be overwritten</source>
+<target>SkaiÄius failų, kurie bus perraÅ¡yti</target>
+
+<source>Number of files and directories that will be deleted</source>
+<target>SkaiÄius failų ir aplankų, kurie bus iÅ¡trinti</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>Items found:</source>
+<target>Rasta elementų:</target>
+
+<source>Speed:</source>
+<target>Greitis:</target>
+
+<source>Remaining time:</source>
+<target>Likęs laikas:</target>
+
+<source>Elapsed time:</source>
+<target>Praėjęs laikas:</target>
+
+<source>Batch job</source>
+<target>Paketinė užduotis</target>
+
+<source>Create a batch file and automate synchronization. To start in batch mode simply double-click this file or run command: FreeFileSync.exe SyncJob.ffs_batch. This can also be scheduled in your system's task planner.</source>
+<target>Sukurti paketinÄ—s užduoties failÄ… ir automatizuoti sinchronizavimÄ…. Kad paleisti paketinÄ—s užduoties veiksenoje tiesiog du kartus spustelÄ—kite ant Å¡io failo arba paleiskite komandÄ…: FreeFileSync.exe SyncJob.ffs_batch. Tai taip pat gali bÅ«ti įtraukta į JÅ«sų sistemos užduoÄių tvarkyklÄ—s planÄ….</target>
+
+<source>Help</source>
+<target>Pagalba</target>
+
+<source>Filter files</source>
+<target>Filtruoti failus</target>
+
+<source>Left</source>
+<target>KairÄ—</target>
+
+<source>Right</source>
+<target>Dešinė</target>
+
+<source>Status feedback</source>
+<target>Būsenos grįžtamasis ryšys</target>
+
+<source>Show progress dialog</source>
+<target>Rodyti eigos langÄ…</target>
+
+<source>Error handling</source>
+<target>Klaidų valdymas</target>
+
+<source>Maximum number of log files:</source>
+<target>Didžiausias ataskaitų failų skaiÄius:</target>
+
+<source>Select log file directory:</source>
+<target>Pažymėti ataskaitos failų aplanką:</target>
+
+<source>Batch settings</source>
+<target>Paketinės užduoties nustatymai</target>
+
+<source>&Save</source>
+<target>&IÅ¡saugoti</target>
+
+<source>&Load</source>
+<target>Ä®&kelti</target>
+
+<source>Select variant:</source>
+<target>Pažymėkite variantą:</target>
+
+<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
+<target>Nustatyti ir siūlyti pokeitimus abiejose pusėse naudojant duomenų bazę. Trinimai, pervardinimas ir konfliktai yra nustatomi automatiškai.</target>
+
+<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
+<target>VeidrodinÄ— kairiojo aplanko kopija. DeÅ¡inysis aplankas yra pakeiÄiamas taip, kad po sinchronizavimo tiksliai atitiktų kairyjį aplankÄ….</target>
+
+<source>Copy new or updated files to right folder.</source>
+<target>Kopijuoti naujus ar atnaujintus failus į dešinyjį aplanką.</target>
+
+<source>Configure your own synchronization rules.</source>
+<target>Nustatyti JÅ«sų paÄių sinchronizavimo taisykles.</target>
+
+<source>Deletion handling</source>
+<target>Trinimo valdymas</target>
+
+<source>On completion:</source>
+<target>Baigus:</target>
+
+<source>Configuration</source>
+<target>Nustatymai</target>
+
+<source>Category</source>
+<target>Kategorija</target>
+
+<source>Action</source>
+<target>Veiksmas</target>
+
+<source>File/folder exists on left side only</source>
+<target>Failas/aplankas egzistuoja tik kairiame aplanke</target>
+
+<source>File/folder exists on right side only</source>
+<target>Failas/aplankas egzistuoja tik dešiniame aplanke</target>
+
+<source>Left file is newer</source>
+<target>Kairysis failas yra naujesnis</target>
+
+<source>Right file is newer</source>
+<target>Dešinysis failas yra naujesnis</target>
+
+<source>Files have different content</source>
+<target>Failai turi skirtingą turinį</target>
+
+<source>Conflict/file cannot be categorized</source>
+<target>Konfliktas/failo negalima kategorizuoti</target>
+
+<source>OK</source>
+<target>Gerai</target>
+
+<source>Compare by...</source>
+<target>Sulyginti pagal...</target>
+
+<source>
+Files are found equal if
+ - last write time and date
+ - file size
+are the same
+</source>
+<target>
+Failai laikomi lygiais jei
+ - paskutinis rašymo laikas ir data
+ - failo dydis
+yra tokie patys
+</target>
+
+<source>
+Files are found equal if
+ - file content
+is the same
+</source>
+<target>
+Failai laikomi lygiais jei
+ - failo turinys
+yra toks pats
+</target>
+
+<source>Symbolic Link handling</source>
+<target>Simbolinių nuorodų valdymas</target>
+
+<source>Synchronizing...</source>
+<target>Sinchronizuojama...</target>
+
+<source>&Pause</source>
+<target>&PauzÄ—</target>
+
+<source>Source code written in C++ utilizing:</source>
+<target>Šaltinio kodas parašytas su C++ naudojant:</target>
+
+<source>Feedback and suggestions are welcome</source>
+<target>NuomonÄ— ir patarimai laukiami</target>
+
+<source>Homepage</source>
+<target>Namų puslapis</target>
+
+<source>FreeFileSync at Sourceforge</source>
+<target>FreeFileSync svetainÄ—je Sourceforge</target>
+
+<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>
+
+<source>Delete on both sides</source>
+<target>IÅ¡trinti abiejose pusÄ—se</target>
+
+<source>Delete on both sides even if the file is selected on one side only</source>
+<target>Ištrinti abiejose pusėse net jei failas yra pažymėtas tik vienoje pusėje</target>
+
+<source>
+Only files that match all filter settings will be synchronized.
+Note: File names must be relative to base directories!
+</source>
+<target>
+Tik failai, kurie atitinka visus filtro nustatymus bus sinchronizuoti.
+Pastaba: Failų pavadinimai privalo atitikti bazinius aplankus!
+</target>
+
+<source>Hints:</source>
+<target>Patarimai:</target>
+
+<source>1. Enter relative file or directory names separated by ';' or a new line.</source>
+<target>1. Įveskite atitinkamus failo ar aplanko pavadinimus atskirtus su ';' ar naujoje eilutėje.</target>
+
+<source>2. Use wildcard characters '*' and '?'.</source>
+<target>2. Naudokite pakaitos simbolius '*' ir '?'.</target>
+
+<source>3. Exclude files directly on main grid via context menu.</source>
+<target>3. Išskirkite failus tiesiogiai pagrindiniame tinklelyje per kontekstinį meniu.</target>
+
+<source>Example</source>
+<target>Pavyzdys</target>
+
+<source>
+Include: *.doc;*.zip;*.exe
+Exclude: \stuff\temp\*
+</source>
+<target>
+Įtraukti: *.doc;*.zip;*.exe
+IÅ¡sirti: \stuff\temp\*
+</target>
+
+<source>Synchronize all .doc, .zip and .exe files except everything in subfolder "temp".</source>
+<target>Sinchronizuoti visus .doc, .zip ir .exe failus iškyrus viską poaplankyje „temp“.</target>
+
+<source>Include</source>
+<target>Įtraukti</target>
+
+<source>Exclude</source>
+<target>Neįtraukti</target>
+
+<source>Time span</source>
+<target>Laiko tarpas</target>
+
+<source>File size</source>
+<target>Failo dydis</target>
+
+<source>Minimum</source>
+<target>Mažiausiai</target>
+
+<source>Maximum</source>
+<target>Daugiausiai</target>
+
+<source>&Default</source>
+<target>&Numatyta</target>
+
+<source>Transactional file copy</source>
+<target>Suderintas failų kopijavimas</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>Pirmiausiai rašyti į laikinąjį failą (*.ffs_tmp), tada pervardinti jį. Tai garantuoja pastovumą net ir kritinės klaidos atveju.</target>
+
+<source>Copy locked files</source>
+<target>Kopijuoti užrakintus failus</target>
+
+<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
+<target>Kopijuoti viešinamus ar užrakintus failus naudojant tomo šėšėlinio kopijavimo tarnybą (Reikalingos administratoriaus teisės)</target>
+
+<source>Copy file access permissions</source>
+<target>Kopijuoti failo leidimus</target>
+
+<source>Transfer file and directory permissions (Requires Administrator rights)</source>
+<target>Perkelti failo ir aplanko leidimus (Reikalingos administratoriaus teisÄ—s)</target>
+
+<source>Restore hidden dialogs</source>
+<target>Atstatyti paslÄ—ptus langus</target>
+
+<source>External applications</source>
+<target>IÅ¡orinÄ—s programos</target>
+
+<source>Description</source>
+<target>Apibūdinimas</target>
+
+<source>Variant</source>
+<target>Variantas</target>
+
+<source>Statistics</source>
+<target>Statistika</target>
+
+<source>Find what:</source>
+<target>Rasti kas:</target>
+
+<source>Match case</source>
+<target>Atitikti atvejÄ…</target>
+
+<source>&Find next</source>
+<target>&Rasti kitÄ…</target>
+
+<source>Operation aborted!</source>
+<target>Operacija nutraukta!</target>
+
+<source>Main bar</source>
+<target>PagrindinÄ— juosta</target>
+
+<source>Folder pairs</source>
+<target>Aplankų poros</target>
+
+<source>Overview</source>
+<target>Apžvalga</target>
+
+<source>Select view</source>
+<target>Pasirinkti rodomus</target>
+
+<source>Set direction:</source>
+<target>Nustatyti kryptį:</target>
+
+<source>Exclude temporarily</source>
+<target>Neįtraukti laikinai</target>
+
+<source>Include temporarily</source>
+<target>Įtraukti laikinai</target>
+
+<source>Exclude via filter:</source>
+<target>Neįtraukti per filtrą:</target>
+
+<source><multiple selection></source>
+<target><keletos pažymėjimas></target>
+
+<source>Delete</source>
+<target>Trinti</target>
+
+<source>Include all</source>
+<target>Įtraukti visus</target>
+
+<source>Exclude all</source>
+<target>Neįtraukti visų</target>
+
+<source>Show icons:</source>
+<target>Rodyti ženkliukus:</target>
+
+<source>Small</source>
+<target>Maži</target>
+
+<source>Medium</source>
+<target>Vidutiniai</target>
+
+<source>Large</source>
+<target>Dideli</target>
+
+<source>Select time span...</source>
+<target>Pasirinkti laiko tarpÄ…...</target>
+
+<source>Default view</source>
+<target>Numatytas rodmuo</target>
+
+<source>Show "%x"</source>
+<target>Rodyti "%x"</target>
+
+<source><Last session></source>
+<target><PaskutinÄ— sesija></target>
+
+<source>Configuration saved!</source>
+<target>Nustatymai išsaugoti!</target>
+
+<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>Configuration loaded!</source>
+<target>Nustatymai įkelti!</target>
+
+<source>Folder Comparison and Synchronization</source>
+<target>Aplankų sulyginimas ir sinchronizavimas</target>
+
+<source>Hide files that exist on left side only</source>
+<target>SlÄ—pti failus, kurie egzistuoja tik kairÄ—je pusÄ—je</target>
+
+<source>Show files that exist on left side only</source>
+<target>Rodyti failus, kurie egzistuoja tik kairÄ—je pusÄ—je</target>
+
+<source>Hide files that exist on right side only</source>
+<target>Slėpti failus, kurie egzistuoja tik dešinėje pusėje</target>
+
+<source>Show files that exist on right side only</source>
+<target>Rodyti failus, kurie egzistuoja tik dešinėje pusėje</target>
+
+<source>Hide files that are newer on left</source>
+<target>SlÄ—pti failus, kurie yra naujesni kairÄ—je</target>
+
+<source>Show files that are newer on left</source>
+<target>Rodyti failus, kurie yra naujesni kairÄ—je</target>
+
+<source>Hide files that are newer on right</source>
+<target>Slėpti failus, kurie yra naujesni dešinėje</target>
+
+<source>Show files that are newer on right</source>
+<target>Rodyti failus, kurie yra naujesni dešinėje</target>
+
+<source>Hide files that are equal</source>
+<target>Slėpti failus, kurie yra lygūs</target>
+
+<source>Show files that are equal</source>
+<target>Rodyti failus, kurie yra lygūs</target>
+
+<source>Hide files that are different</source>
+<target>SlÄ—pti failus, kurie yra skirtingi</target>
+
+<source>Show files that are different</source>
+<target>Rodyti failus, kurie yra skirtingi</target>
+
+<source>Hide conflicts</source>
+<target>SlÄ—pti konfliktus</target>
+
+<source>Show conflicts</source>
+<target>Rodyti konfliktus</target>
+
+<source>Hide files that will be created on the left side</source>
+<target>SlÄ—pti failus, kurie bus sukurti kairÄ—je pusÄ—je</target>
+
+<source>Show files that will be created on the left side</source>
+<target>Rodyti failus, kurie bus sukurti kairÄ—je pusÄ—je</target>
+
+<source>Hide files that will be created on the right side</source>
+<target>Slėpti failus, kurie bus sukurti dešinėje pusėje</target>
+
+<source>Show files that will be created on the right side</source>
+<target>Rodyti failus, kurie bus sukurti dešinėje pusėje</target>
+
+<source>Hide files that will be deleted on the left side</source>
+<target>Slėpti failus, kurie bus ištrinti kairėje pusėje</target>
+
+<source>Show files that will be deleted on the left side</source>
+<target>Rodyti failus, kurie bus ištrinti kairėje pusėje</target>
+
+<source>Hide files that will be deleted on the right side</source>
+<target>Slėpti failus, kurie bus ištrinti dešinėje pusėje</target>
+
+<source>Show files that will be deleted on the right side</source>
+<target>Rodyti failus, kurie bus ištrinti dešinėje pusėje</target>
+
+<source>Hide files that will be overwritten on left side</source>
+<target>Slėpti failus, kurie bus perrašyti kairėje pusėje</target>
+
+<source>Show files that will be overwritten on left side</source>
+<target>Rodyti failus, kurie bus perrašyti kairėje pusėje</target>
+
+<source>Hide files that will be overwritten on right side</source>
+<target>Slėpti failus, kurie bus perrašyti dešinėje pusėje</target>
+
+<source>Show files that will be overwritten on right side</source>
+<target>Rodyti failus, kurie bus perrašyti dešinėje pusėje</target>
+
+<source>Hide files that won't be copied</source>
+<target>SlÄ—pti failus, kurie ne bus kopijuojami</target>
+
+<source>Show files that won't be copied</source>
+<target>Rodyti failus, kurie ne bus kopijuojami</target>
+
+<source>All directories in sync!</source>
+<target>Visi aplankai sinchronizavime!</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>
+
+<source>Legend</source>
+<target>Legenda</target>
+
+<source>File list exported!</source>
+<target>Failų sąrašas eksportuotas!</target>
+
+<source>
+<pluralform>Object deleted successfully!</pluralform>
+<pluralform>%x objects deleted successfully!</pluralform>
+</source>
+<target>
+<pluralform>Objektas sėkmingai ištrintas!</pluralform>
+<pluralform>%x objektai sėkmingai ištrinti!</pluralform>
+<pluralform>%x objektų sėkmingai ištrinti!</pluralform>
+<pluralform>%x objektai sėkmingai ištrinti!</pluralform>
+</target>
+
+<source>
+<pluralform>1 directory</pluralform>
+<pluralform>%x directories</pluralform>
+</source>
+<target>
+<pluralform>1 aplankas</pluralform>
+<pluralform>%x aplankai</pluralform>
+<pluralform>%x aplankų</pluralform>
+<pluralform>%x aplankai</pluralform>
+</target>
+
+<source>
+<pluralform>1 file</pluralform>
+<pluralform>%x files</pluralform>
+</source>
+<target>
+<pluralform>1 failas</pluralform>
+<pluralform>%x failai</pluralform>
+<pluralform>%x failų</pluralform>
+<pluralform>%x failai</pluralform>
+</target>
+
+<source>
+<pluralform>%x of 1 row in view</pluralform>
+<pluralform>%x of %y rows in view</pluralform>
+</source>
+<target>
+<pluralform>%x iš 1 eilės rodmenyje</pluralform>
+<pluralform>%x iš %y eilių rodmenyje</pluralform>
+<pluralform>%x iš %y eilių rodmenyje</pluralform>
+<pluralform>%x iš %y eilių rodmenyje</pluralform>
+</target>
+
+<source>Scanning...</source>
+<target>Skenuojama...</target>
+
+<source>Comparing content...</source>
+<target>Sulyginamas turinys...</target>
+
+<source>Paused</source>
+<target>Pristabdyta</target>
+
+<source>Initializing...</source>
+<target>Pradedama...</target>
+
+<source>Aborted</source>
+<target>Nutraukta</target>
+
+<source>Completed</source>
+<target>Baigta</target>
+
+<source>Continue</source>
+<target>Tęsti</target>
+
+<source>Pause</source>
+<target>Pristabdyti</target>
+
+<source>Cannot find %x</source>
+<target>Nepavyksta rasti %x</target>
+
+<source>Inactive</source>
+<target>Neaktyvus</target>
+
+<source>Today</source>
+<target>Å iandien</target>
+
+<source>This week</source>
+<target>Å i savaitÄ—</target>
+
+<source>This month</source>
+<target>Å is mÄ—nuo</target>
+
+<source>This year</source>
+<target>Å ie metai</target>
+
+<source>Last x days</source>
+<target>PaskutinÄ—s x dienos</target>
+
+<source>Byte</source>
+<target>Baitai</target>
+
+<source>KB</source>
+<target>KB</target>
+
+<source>MB</source>
+<target>MB</target>
+
+<source>Filter</source>
+<target>Filtras</target>
+
+<source>Direct</source>
+<target>Tiesiogiai</target>
+
+<source>Follow</source>
+<target>Sekti</target>
+
+<source>Copy NTFS permissions</source>
+<target>Kopijuoti NTFS leidimus</target>
+
+<source>Integrate external applications into context menu. The following macros are available:</source>
+<target>Integruoti išorines programas į kontekstinį meniu. Sekantys makro galimi:</target>
+
+<source>- full file or directory name</source>
+<target>- pilnas failo ar aplanko pavadinimas</target>
+
+<source>- directory part only</source>
+<target>- tik aplanko dalis</target>
+
+<source>- Other side's counterpart to %name</source>
+<target>- Kitos pusÄ—s atitikmuo %name</target>
+
+<source>- Other side's counterpart to %dir</source>
+<target>- Kitos pusÄ—s atitikmuo %dir</target>
+
+<source>Make hidden dialogs and warning messages visible again?</source>
+<target>Padaryti paslėptus langus ir perpėjimo žinutes matomas vėl?</target>
+
+<source>
+<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
+<pluralform>Do you really want to move the following %x objects to the Recycle Bin?</pluralform>
+</source>
+<target>
+<pluralform>Ar tikrai norite perkelti sekantį objektą į šiukšliadėžę?</pluralform>
+<pluralform>Ar tikrai norite perkelti sekanÄius %x objektus į Å¡iukÅ¡liadėžę?</pluralform>
+<pluralform>Ar tikrai norite perkelti sekanÄius %x objektų į Å¡iukÅ¡liadėžę?</pluralform>
+<pluralform>Ar tikrai norite perkelti sekanÄius %x objektus į Å¡iukÅ¡liadėžę?</pluralform>
+</target>
+
+<source>
+<pluralform>Do you really want to delete the following object?</pluralform>
+<pluralform>Do you really want to delete the following %x objects?</pluralform>
+</source>
+<target>
+<pluralform>Ar tikrai norite ištrinti sekantį objektą?</pluralform>
+<pluralform>Ar tikrai norite iÅ¡trinti sekantÄius %x objektus?</pluralform>
+<pluralform>Ar tikrai norite iÅ¡trinti sekantÄius %x objektų?</pluralform>
+<pluralform>Ar tikrai norite iÅ¡trinti sekantÄius %x objektus?</pluralform>
+</target>
+
+<source>Leave as unresolved conflict</source>
+<target>Palikti kaip neišpręstą konfliktą</target>
+
+<source>Delete permanently</source>
+<target>IÅ¡trinti visam laikui</target>
+
+<source>Delete or overwrite files permanently</source>
+<target>Trinti ar perrašyti failus visam laikui</target>
+
+<source>Use Recycle Bin when deleting or overwriting files</source>
+<target>Naudoti šiukšliadėžę kaii trinami ar perrašomi failai</target>
+
+<source>Versioning</source>
+<target>Versijavimas</target>
+
+<source>Move files into a time-stamped subdirectory</source>
+<target>Perkelti failus į laiku pažymėtą poaplankį</target>
+
+<source>Files</source>
+<target>Failai</target>
+
+<source>Percentage</source>
+<target>Procentai</target>
+
+<source>%x TB</source>
+<target>%x TB</target>
+
+<source>%x PB</source>
+<target>%x PB</target>
+
+<source>%x%</source>
+<target>%x%</target>
+
+<source>
+<pluralform>1 min</pluralform>
+<pluralform>%x min</pluralform>
+</source>
+<target>
+<pluralform>1 min</pluralform>
+<pluralform>%x min</pluralform>
+<pluralform>%x min</pluralform>
+<pluralform>%x min</pluralform>
+</target>
+
+<source>
+<pluralform>1 hour</pluralform>
+<pluralform>%x hours</pluralform>
+</source>
+<target>
+<pluralform>1 valanda</pluralform>
+<pluralform>%x valandos</pluralform>
+<pluralform>%x valandų</pluralform>
+<pluralform>%x valandos</pluralform>
+</target>
+
+<source>
+<pluralform>1 day</pluralform>
+<pluralform>%x days</pluralform>
+</source>
+<target>
+<pluralform>1 diena</pluralform>
+<pluralform>%x dienos</pluralform>
+<pluralform>%x dienų</pluralform>
+<pluralform>%x dienos</pluralform>
+</target>
+
+<source>Cannot monitor directory %x.</source>
+<target>Nepavyko stebÄ—ti aplanko %x.</target>
+
+<source>Conversion error:</source>
+<target>Konvertavimo klaida:</target>
+
+<source>Cannot delete file %x.</source>
+<target>Nepavyksta ištrinti failo %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Failas yra užrakintas kito procceso:</target>
+
+<source>Cannot move file %x to %y.</source>
+<target>Nepavyksta perkelti failo %x į %y.</target>
+
+<source>Cannot delete directory %x.</source>
+<target>Nepavyksta ištrinti aplanko %x.</target>
+
+<source>Cannot write modification time of %x.</source>
+<target>Nepavyksta šrašyti pakeitimo datos %x.</target>
+
+<source>Cannot find system function %x.</source>
+<target>Nepavyksta rasti sistemos funkcijos %x.</target>
+
+<source>Cannot read security context of %x.</source>
+<target>Nepavyksta perskaityti %x saugumo konteksto.</target>
+
+<source>Cannot write security context of %x.</source>
+<target>Nepavyksta įrašyti %x saugumo konteksto.</target>
+
+<source>Cannot read permissions of %x.</source>
+<target>Nepavyksta perskaityti %x leidimų.</target>
+
+<source>Cannot write permissions of %x.</source>
+<target>Nepavyksta įrašyti leidimų %x.</target>
+
+<source>Cannot create directory %x.</source>
+<target>Nepavyksta sukurti aplanko %x.</target>
+
+<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>
+
+<source>Cannot read directory %x.</source>
+<target>Nepavyksta nuskaityti aplanko %x.</target>
+
+<source>Endless loop.</source>
+<target>Nesibaigiantis ciklas</target>
+
+<source>Cannot set privilege %x.</source>
+<target>Nepavyksta nustatyti privilegijos %x.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Nepavyksta perkelti %x į šiukšliadėžę!</target>
+
+<source>Both sides have changed since last synchronization!</source>
+<target>Abi pusÄ—s buvo pakeistos nuo paskutinio sinchronizavimo!</target>
+
+<source>Cannot determine sync-direction:</source>
+<target>Nepavyksta nustatyti sinchronizavimo krypties:</target>
+
+<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>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>
+
+<source>The file does not contain a valid configuration:</source>
+<target>Failas neturi tinkamų nustatymų:</target>
+
+<source>You can ignore this error to consider the directory as empty.</source>
+<target>JÅ«s galite ignoruoti Å¡iÄ… klaidÄ…, kad laikyti aplankÄ… tuÅ¡Äiu.</target>
+
+<source>Cannot find directory %x.</source>
+<target>Nepavyksta rasti aplanko %x</target>
+
+<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
+<target>Aplankai yra priklausomi! Būkite atsargūs nustatydami sinchronizavimo taisykles:</target>
+
+<source>Preparing synchronization...</source>
+<target>Ruošiamas sinchronizavimas...</target>
+
+<source>Conflict detected:</source>
+<target>Aptiktas konfliktas:</target>
+
+<source>File %x has an invalid date!</source>
+<target>Failas %x turi netinkamÄ… datÄ…!</target>
+
+<source>Files %x have the same date but a different size!</source>
+<target>Failai %x turi tokiÄ… paÄiÄ… datÄ… bet skirtingÄ… dydį!</target>
+
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>SimbolinÄ—s nuorodos %x turi tokiÄ… paÄiÄ… datÄ… bet skirtingus tikslus</target>
+
+<source>Comparing content of files %x</source>
+<target>Sulyginamas failų turinys %x</target>
+
+<source>Comparing files by content failed.</source>
+<target>Nepavyko failų sulyginimas pagal turinį.</target>
+
+<source>Generating file list...</source>
+<target>Generuojamas failų sąrašas...</target>
+
+<source>Both sides are equal</source>
+<target>Abi pusÄ—s yra lygios</target>
+
+<source>Files/folders differ in attributes only</source>
+<target>Failai/aplankai skiriasi tik pagal atributus</target>
+
+<source>Copy new file/folder to left</source>
+<target>Kopijuoti naują failą/aplanką į kairę</target>
+
+<source>Copy new file/folder to right</source>
+<target>Kopijuoti naują failą/aplanką į dešinę</target>
+
+<source>Delete left file/folder</source>
+<target>Trinti kairį failą/aplanką</target>
+
+<source>Delete right file/folder</source>
+<target>Trinti dešinį failą/aplanką</target>
+
+<source>Move file on left</source>
+<target>Perkelti failą į kairę</target>
+
+<source>Move file on right</source>
+<target>Perkelti failą į dešinę</target>
+
+<source>Overwrite left file/folder with right one</source>
+<target>Perrašyti kairį failą/aplanką su dešiniuoju</target>
+
+<source>Overwrite right file/folder with left one</source>
+<target>Perrašyti dešinįjį failą/aplanką su kairiuoju</target>
+
+<source>Do nothing</source>
+<target>Nieko nedaryti</target>
+
+<source>Copy file attributes only to left</source>
+<target>Kopijuoti failo atributus tik į kairę</target>
+
+<source>Copy file attributes only to right</source>
+<target>Kopijuoti failo atributus tik į dešinę</target>
+
+<source>Multiple...</source>
+<target>Keletas...</target>
+
+<source>Deleting file %x</source>
+<target>Trinamas failas %x</target>
+
+<source>Deleting folder %x</source>
+<target>Trinamas aplankas %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Tinama simbolinÄ— nuoroda %x</target>
+
+<source>Moving file %x to recycle bin</source>
+<target>Perkeliamas failas %x į šiukšliadėžę</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>Perkeliamas aplankas %x į šiukšliadėžę</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>Perkeliama simbolinė nuoroda %x į šiukšliadėžę</target>
+
+<source>Moving file %x to %y</source>
+<target>Perkeliamas failas %x į %y</target>
+
+<source>Moving folder %x to %y</source>
+<target>Perkeliamas aplankas %x į %y</target>
+
+<source>Moving symbolic link %x to %y</source>
+<target>Perkeliama simbolinė nuoroda %x į %y</target>
+
+<source>Creating file %x</source>
+<target>Kuriamas failas %x</target>
+
+<source>Creating symbolic link %x</source>
+<target>Kuriama simbolinÄ— nuoroda %x</target>
+
+<source>Creating folder %x</source>
+<target>Kuriamas aplankas %x</target>
+
+<source>Overwriting file %x</source>
+<target>Perrašomas failas %x</target>
+
+<source>Overwriting symbolic link %x</source>
+<target>Perrašoma simbolinė nuoroda %x</target>
+
+<source>Verifying file %x</source>
+<target>Tikrinamas failas %x</target>
+
+<source>Updating attributes of %x</source>
+<target>Atnaujinami atributai %x</target>
+
+<source>Target directory name must not be empty!</source>
+<target>Tikslo aplankas privalo bÅ«ti ne tuÅ¡Äias!</target>
+
+<source>Directory for file versioning was not supplied!</source>
+<target>Aplankas failo versijavimui nebuvo pateiktas!</target>
+
+<source>Source directory %x not found.</source>
+<target>Å altinio aplankas %x nerastas.</target>
+
+<source>Unresolved conflicts existing!</source>
+<target>Yra neišspręstų konfliktų!</target>
+
+<source>You can ignore conflicts and continue synchronization.</source>
+<target>Jūs galite ignoruoti konfliktus ir tęsti sinchronizavimą.</target>
+
+<source>Significant difference detected:</source>
+<target>Žymus skirtumas nustatytas:</target>
+
+<source>More than 50% of the total number of files will be copied or deleted!</source>
+<target>Daugiau nei 50% failų bus nukopijuota arba ištrinta!</target>
+
+<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>Free disk space available:</source>
+<target>Laisva disko vieta prieinama:</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>
+
+<source>A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!</source>
+<target>Aplankas, kuris bus keiÄiamas yra dalis keletos aplankų porų! PraÅ¡ome peržiÅ«rÄ—ti sinchronizavimo nustatymus!</target>
+
+<source>Processing folder pair:</source>
+<target>Apdorojama aplankų pora:</target>
+
+<source>Generating database...</source>
+<target>Generuojama duomenų bazė...</target>
+
+<source>Data verification error: Source and target file have different content!</source>
+<target>Duomenų patikrinimo klaida: Šaltinio ir tikslo failas turi skirtingus turinius!</target>
+
diff --git a/BUILD/Languages/norwegian.lng b/BUILD/Languages/norwegian.lng
new file mode 100644
index 00000000..31474eb8
--- /dev/null
+++ b/BUILD/Languages/norwegian.lng
@@ -0,0 +1,1463 @@
+<header>
+ <language name>Norsk</language name>
+ <translator>FreewareTips</translator>
+ <locale>nb_NO</locale>
+ <flag file>norway.png</flag file>
+ <plural forms>2</plural forms>
+ <plural definition>n == 1 ? 0 : 1</plural definition>
+</header>
+
+<source>Searching for directory %x...</source>
+<target>Søker etter mappe %x...</target>
+
+<source>Show in Explorer</source>
+<target>Vis i Utforsker</target>
+
+<source>Open with default application</source>
+<target>Ã…pne med standardprogram</target>
+
+<source>Browse directory</source>
+<target>Bla gjennom mappe</target>
+
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Avbrytelse forespurt: Venter på at gjeldende handling avsluttes...</target>
+
+<source>RealtimeSync - Automated Synchronization</source>
+<target>RealtimeSync - Automatisk synkronisering</target>
+
+<source>Error</source>
+<target>Feil</target>
+
+<source>Select alternate comparison settings</source>
+<target>Velg alternative sammenligningsinnstillinger</target>
+
+<source>Select alternate synchronization settings</source>
+<target>Velg alternative synkroniseringsinnstillinger</target>
+
+<source>No filter selected</source>
+<target>Ingen filter valgt</target>
+
+<source>Filter is active</source>
+<target>Filter er aktivt</target>
+
+<source>Remove alternate settings</source>
+<target>Fjern alternative innstillinger</target>
+
+<source>Clear filter settings</source>
+<target>Fjern filterinnstillinger</target>
+
+<source>Create a batch job</source>
+<target>Opprett en batch-jobb</target>
+
+<source>Synchronization settings</source>
+<target>Synkroniseringsinnstillinger</target>
+
+<source>Comparison settings</source>
+<target>Sammenligningsinnstillinger</target>
+
+<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>
+
+<source>Configure filter</source>
+<target>Still inn filter</target>
+
+<source>Global settings</source>
+<target>Felles innstillinger</target>
+
+<source>Synchronization Preview</source>
+<target>Forhåndsvisning for synkronisering</target>
+
+<source>Find</source>
+<target>Søk</target>
+
+<source>Select time span</source>
+<target>Velg tidsområde</target>
+
+<source>Show pop-up</source>
+<target>Vis oppsprettsvindu</target>
+
+<source>Show pop-up on errors or warnings</source>
+<target>Vis oppsprettsvindu ved feil eller advarsler</target>
+
+<source>Ignore errors</source>
+<target>Ignorer feil</target>
+
+<source>Hide all error and warning messages</source>
+<target>Skjul meldinger om feil og advarsler</target>
+
+<source>Exit instantly</source>
+<target>Avslutt med en gang</target>
+
+<source>Abort synchronization immediately</source>
+<target>Avbryt synkronisering umiddelbart</target>
+
+<source>Browse</source>
+<target>Bla gjennom</target>
+
+<source>Invalid command line: %x</source>
+<target>Ugyldig kommando: %x</target>
+
+<source>Info</source>
+<target>Info</target>
+
+<source>Fatal Error</source>
+<target>Fatal feil</target>
+
+<source>Windows Error Code %x:</source>
+<target>Windows feilkode %x:</target>
+
+<source>Linux Error Code %x:</source>
+<target>Linux feilkode %x:</target>
+
+<source>Cannot resolve symbolic link %x.</source>
+<target>Kan ikke bestemme symbolsk lenke %x.</target>
+
+<source>%x MB</source>
+<target>%x MB</target>
+
+<source>%x KB</source>
+<target>%x KB</target>
+
+<source>%x GB</source>
+<target>%x GB</target>
+
+<source>
+<pluralform>1 Byte</pluralform>
+<pluralform>%x Bytes</pluralform>
+</source>
+<target>
+<pluralform>1 Byte</pluralform>
+<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>
+
+<source>Initial synchronization:</source>
+<target>Innledende synkronisering:</target>
+
+<source>Database file %x does not yet exist.</source>
+<target>Databasefil %x finnes ikke ennå.</target>
+
+<source>Out of memory!</source>
+<target>For lite minne!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Databasefiler deler ikke en felles synkroniseringsøkt.</target>
+
+<source>An exception occurred!</source>
+<target>En unntagelse skjedde!</target>
+
+<source>Cannot read file attributes of %x.</source>
+<target>Kan ikke lese filattributter til %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Kan ikke hente prosessinformasjon.</target>
+
+<source>Waiting while directory is locked (%x)...</source>
+<target>Venter mens mappe er låst (%x)...</target>
+
+<source>Cannot set directory lock %x.</source>
+<target>Kan ikke sette mappelås %x.</target>
+
+<source>
+<pluralform>1 sec</pluralform>
+<pluralform>%x sec</pluralform>
+</source>
+<target>
+<pluralform>1 sek</pluralform>
+<pluralform>%x sek</pluralform>
+</target>
+
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Feil ved analysering av fil %x, rekke %y, kolonne %z.</target>
+
+<source>Scanning:</source>
+<target>Skanner:</target>
+
+<source>Encoding extended time information: %x</source>
+<target>Koder utvided tidsinformasjon: %x</target>
+
+<source>
+<pluralform>[1 Thread]</pluralform>
+<pluralform>[%x Threads]</pluralform>
+</source>
+<target>
+<pluralform>[1 Tråd]</pluralform>
+<pluralform>[%x Tråder]</pluralform>
+</target>
+
+<source>/sec</source>
+<target>/sek</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Filen %x inneholder ikke en gyldig innstilling.</target>
+
+<source>Configuration file %x loaded partially only.</source>
+<target>Innstillingsfilen %x bare delvis lastet.</target>
+
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Kan ikke få adgang til Volume Shadow Copy Service.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Bruk FreeFileSync 64-bit-versjon til å opprette skyggekopier på dette systemet.</target>
+
+<source>Cannot load file %x.</source>
+<target>Kan ikke laste filen %x.</target>
+
+<source>Path %x does not contain a volume name.</source>
+<target>Banen %x inneholder ikke et volumnavn.</target>
+
+<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>S&ave configuration...</source>
+<target>L&agre innstilling...</target>
+
+<source>&Load configuration...</source>
+<target>&Last innstilling...</target>
+
+<source>&Quit</source>
+<target>&Avslutt</target>
+
+<source>&File</source>
+<target>&Fil</target>
+
+<source>&Content</source>
+<target>&Innhold</target>
+
+<source>&About...</source>
+<target>&Om programmet...</target>
+
+<source>&Help</source>
+<target>&Hjelp</target>
+
+<source>Usage:</source>
+<target>Bruk:</target>
+
+<source>1. Select directories to monitor.</source>
+<target>1. Velg mapper å overvåke.</target>
+
+<source>2. Enter a command line.</source>
+<target>2. Oppfør en kommandolinje.</target>
+
+<source>3. Press 'Start'.</source>
+<target>3. Trykk 'Start'.</target>
+
+<source>
+The command line is executed each time:
+- all directories become available (e.g. USB stick insert)
+- files within these directories or subdirectories are modified
+</source>
+<target>
+Kommandolinjen kjøres hver gang:
+- Alle mapper blir tilgjengelige (f.eks. ved innsetting av USB-minnepinne)
+- Filer i disse mapper eller undermapper endres
+</target>
+
+<source>Directories to watch</source>
+<target>Mapper å overvåke</target>
+
+<source>Add folder</source>
+<target>Legg til mappe</target>
+
+<source>Remove folder</source>
+<target>Fjern mappe</target>
+
+<source>Select a folder</source>
+<target>Velg en mappe</target>
+
+<source>Command line</source>
+<target>Kommandolinje</target>
+
+<source>Minimum Idle Time [seconds]</source>
+<target>Minimum pausetid [sekunder]</target>
+
+<source>Idle time between detection of last change and execution of command line in seconds</source>
+<target>Uvirksom tid mellom oppdaging av siste endring og kjøring av kommandolinje i sekunder</target>
+
+<source>Start</source>
+<target>Start</target>
+
+<source>&Retry</source>
+<target>&Prøv igjen</target>
+
+<source>Cancel</source>
+<target>Avbryt</target>
+
+<source>(Build: %x)</source>
+<target>(Build: %x)</target>
+
+<source>RealtimeSync configuration</source>
+<target>RealtimeSync-innstilling</target>
+
+<source>&Restore</source>
+<target>&Gjenopprett</target>
+
+<source>&Exit</source>
+<target>&Avslutt</target>
+
+<source>Monitoring active...</source>
+<target>Overvåkning aktiv...</target>
+
+<source>Waiting for missing directories...</source>
+<target>Venter på manglende mapper...</target>
+
+<source>A directory input field is empty.</source>
+<target>Et inndatafelt for mappe er tomt.</target>
+
+<source>Logging</source>
+<target>Logging</target>
+
+<source>File time and size</source>
+<target>Fildato og størrelse</target>
+
+<source>File content</source>
+<target>Filinnhold</target>
+
+<source><Automatic></source>
+<target><Automatisk></target>
+
+<source>Mirror ->></source>
+<target>Speile ->></target>
+
+<source>Update -></source>
+<target>Oppdatere -></target>
+
+<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>Batch execution</source>
+<target>Batch-kjøring</target>
+
+<source>Items processed:</source>
+<target>Elementer behandlet:</target>
+
+<source>Items remaining:</source>
+<target>Elementer igjen:</target>
+
+<source>Total time:</source>
+<target>Total tid:</target>
+
+<source>Stop</source>
+<target>Stopp</target>
+
+<source>Synchronization aborted!</source>
+<target>Synkronisering avbrutt!</target>
+
+<source>Synchronization completed with errors!</source>
+<target>Synkronisering fullført med feil!</target>
+
+<source>Nothing to synchronize!</source>
+<target>Ikke noe å synkronisere!</target>
+
+<source>Synchronization completed successfully!</source>
+<target>Synkronisering vellykket fullført!</target>
+
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Trykk "Skift" for å løse problemer i FreeFileSync hovedvindu.</target>
+
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Skifter til FreeFileSync hovedvindu...</target>
+
+<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>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>Do you want FreeFileSync to automatically check for updates every week?</source>
+<target>Skal FreeFileSync automatisk se etter oppdateringer hver uke?</target>
+
+<source>(Requires an Internet connection!)</source>
+<target>(Krever en internettforbindelse!)</target>
+
+<source><Symlink></source>
+<target><Symbolsk lenke></target>
+
+<source><Directory></source>
+<target><Mappe></target>
+
+<source>Full path</source>
+<target>Full bane</target>
+
+<source>Name</source>
+<target>Navn</target>
+
+<source>Relative path</source>
+<target>Relativ bane</target>
+
+<source>Directory</source>
+<target>Mappe</target>
+
+<source>Size</source>
+<target>Størrelse</target>
+
+<source>Date</source>
+<target>Dato</target>
+
+<source>Extension</source>
+<target>Filendelse</target>
+
+<source>Comparison Result</source>
+<target>Sammenligningsresultat</target>
+
+<source>Drag && drop</source>
+<target>Dra && slipp</target>
+
+<source>Close progress dialog</source>
+<target>Lukk framdriftsvindu</target>
+
+<source>Shut down</source>
+<target>Slå av maskinen</target>
+
+<source>Log off</source>
+<target>Logg av</target>
+
+<source>Standby</source>
+<target>Standby</target>
+
+<source>Hibernate</source>
+<target>Sett i dvalemodus</target>
+
+<source>1. &Compare</source>
+<target>1. Sammen&lign</target>
+
+<source>2. &Synchronize...</source>
+<target>2. &Synkroniser...</target>
+
+<source>&New</source>
+<target>&Ny</target>
+
+<source>&Program</source>
+<target>&Program</target>
+
+<source>&Language</source>
+<target>&Språk</target>
+
+<source>&Global settings...</source>
+<target>&Felles innstillinger...</target>
+
+<source>&Create batch job...</source>
+<target>&Opprett batch-jobb...</target>
+
+<source>&Export file list...</source>
+<target>&Eksporter filliste...</target>
+
+<source>&Advanced</source>
+<target>&Avansert</target>
+
+<source>&Check for new version</source>
+<target>&Se etter ny versjon</target>
+
+<source>Compare</source>
+<target>Sammenlign</target>
+
+<source>Compare both sides</source>
+<target>Sammenlign begge sider</target>
+
+<source>&Abort</source>
+<target>&Avbryt</target>
+
+<source>Synchronize...</source>
+<target>Synkroniser...</target>
+
+<source>Start synchronization</source>
+<target>Start synkronisering</target>
+
+<source>Add folder pair</source>
+<target>Legg til mappepar</target>
+
+<source>Remove folder pair</source>
+<target>Fjern mappepar</target>
+
+<source>Swap sides</source>
+<target>Bytt sider</target>
+
+<source>Save current configuration to file</source>
+<target>Lagre gjeldende innstilling til fil</target>
+
+<source>Load configuration from file</source>
+<target>Last innstilling fra fil</target>
+
+<source>Last used configurations (press DEL to remove from list)</source>
+<target>Sist brukte innstillinger (trykk DEL for å fjerne fra liste)</target>
+
+<source>Hide excluded items</source>
+<target>Skjul ekskluderte elementer</target>
+
+<source>Hide filtered or temporarily excluded files</source>
+<target>Skjul filtrerte eller midlertidig ekskluderte filer</target>
+
+<source>Number of files and directories that will be created</source>
+<target>Antall filer og mapper som blir opprettet</target>
+
+<source>Number of files that will be overwritten</source>
+<target>Antall filer som blir overskrevet</target>
+
+<source>Number of files and directories that will be deleted</source>
+<target>Antal filer og mapper som blir slettet</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>Items found:</source>
+<target>Elementer funnet:</target>
+
+<source>Speed:</source>
+<target>Hastighet:</target>
+
+<source>Remaining time:</source>
+<target>Gjenstående tid:</target>
+
+<source>Elapsed time:</source>
+<target>Tid gått:</target>
+
+<source>Batch job</source>
+<target>Batch-jobb</target>
+
+<source>Create a batch file and automate synchronization. To start in batch mode simply double-click this file or run command: FreeFileSync.exe SyncJob.ffs_batch. This can also be scheduled in your system's task planner.</source>
+<target>Opprett en batch-fil og automatiser synkronisering. For å starte i batch-modus dobbeltklikk denne filen eller kjør kommandoen: FreeFileSync.exe SyncJob.ffs_batch. Dette kan også planlegges i ditt systems oppgaveplanlegger.</target>
+
+<source>Help</source>
+<target>Hjelp</target>
+
+<source>Filter files</source>
+<target>Filtrer filer</target>
+
+<source>Left</source>
+<target>Venstre</target>
+
+<source>Right</source>
+<target>Høyre</target>
+
+<source>Status feedback</source>
+<target>Status-tilbakemelding</target>
+
+<source>Show progress dialog</source>
+<target>Vis dialogboks</target>
+
+<source>Error handling</source>
+<target>Feilhåndtering</target>
+
+<source>Maximum number of log files:</source>
+<target>Maksimale antall loggfiler:</target>
+
+<source>Select log file directory:</source>
+<target>Velg loggfilmappe:</target>
+
+<source>Batch settings</source>
+<target>Batch-innstillinger</target>
+
+<source>&Save</source>
+<target>La&gre</target>
+
+<source>&Load</source>
+<target>&Last</target>
+
+<source>Select variant:</source>
+<target>Velg variant:</target>
+
+<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
+<target>Identifiser og spre endringer på begge sider ved å bruke en database. Slettinger, navneendringer og konflikter blir automatisk oppdaget.</target>
+
+<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
+<target>Speilings-sikkerhetskopi av venstre mappe. Høyre mappe endres slik at den blir helt lik venstre mappe etter synkronisering.</target>
+
+<source>Copy new or updated files to right folder.</source>
+<target>Kopier nye og endrede filer til høyre mappe.</target>
+
+<source>Configure your own synchronization rules.</source>
+<target>Still inn dine egne synkroniseringsregler.</target>
+
+<source>Deletion handling</source>
+<target>Slette-håndtering</target>
+
+<source>On completion:</source>
+<target>Ved fullføring:</target>
+
+<source>Configuration</source>
+<target>Innstilling</target>
+
+<source>Category</source>
+<target>Kategori</target>
+
+<source>Action</source>
+<target>Handling</target>
+
+<source>File/folder exists on left side only</source>
+<target>Fil/mappe finnes bare på venstre side</target>
+
+<source>File/folder exists on right side only</source>
+<target>Fil/mappe finnes bare på høyre side</target>
+
+<source>Left file is newer</source>
+<target>Fil til venstre er nyere</target>
+
+<source>Right file is newer</source>
+<target>Fil til høyre er nyere</target>
+
+<source>Files have different content</source>
+<target>Filer har forskjellig innhold</target>
+
+<source>Conflict/file cannot be categorized</source>
+<target>Konflikt/filen kan ikke kategoriseres</target>
+
+<source>OK</source>
+<target>OK</target>
+
+<source>Compare by...</source>
+<target>Sammenlign etter...</target>
+
+<source>
+Files are found equal if
+ - last write time and date
+ - file size
+are the same
+</source>
+<target>
+Filer blir funnet like hvis
+ - sist skrevne tid og dato
+ - filstørrelse
+er den samme
+</target>
+
+<source>
+Files are found equal if
+ - file content
+is the same
+</source>
+<target>
+Filer blir funnet like hvis
+ - filinnhold
+er det samme
+</target>
+
+<source>Symbolic Link handling</source>
+<target>Symbolsk lenkehåndtering</target>
+
+<source>Synchronizing...</source>
+<target>Synkroniserer...</target>
+
+<source>&Pause</source>
+<target>&Pause</target>
+
+<source>Source code written in C++ utilizing:</source>
+<target>Kildekode skrevet i C++ med hjelp fra:</target>
+
+<source>Feedback and suggestions are welcome</source>
+<target>Tilbakemelding og forslag er velkomne</target>
+
+<source>Homepage</source>
+<target>Hjemmeside</target>
+
+<source>FreeFileSync at Sourceforge</source>
+<target>FreeFileSync på Sourceforge</target>
+
+<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>
+
+<source>Delete on both sides</source>
+<target>Slett på begge sider</target>
+
+<source>Delete on both sides even if the file is selected on one side only</source>
+<target>Slett på begge sider selv om filen bare er valgt på en side</target>
+
+<source>
+Only files that match all filter settings will be synchronized.
+Note: File names must be relative to base directories!
+</source>
+<target>
+Synkroniserer kun filer som passer til alle filterinnstillinger.
+Merk: Filnavn må være relative til basismapper!
+</target>
+
+<source>Hints:</source>
+<target>Veiledninger:</target>
+
+<source>1. Enter relative file or directory names separated by ';' or a new line.</source>
+<target>1. Oppfør relative fil- eller mappenavn adskilt med ';' eller en ny linje.</target>
+
+<source>2. Use wildcard characters '*' and '?'.</source>
+<target>2. Bruk jokertegn '*' og '?'.</target>
+
+<source>3. Exclude files directly on main grid via context menu.</source>
+<target>3. Ekskluder filer direkte i hovedvindu via høyreklikkmeny.</target>
+
+<source>Example</source>
+<target>Eksempel</target>
+
+<source>
+Include: *.doc;*.zip;*.exe
+Exclude: \stuff\temp\*
+</source>
+<target>
+Inkluder: *.doc;*.zip;*.exe
+Ekskluder: \ting\temp\*
+</target>
+
+<source>Synchronize all .doc, .zip and .exe files except everything in subfolder "temp".</source>
+<target>Synkroniserer alle .doc, .zip og .exe-filer unntatt alt i undermappen "temp".</target>
+
+<source>Include</source>
+<target>Inkluder</target>
+
+<source>Exclude</source>
+<target>Ekskluder</target>
+
+<source>Time span</source>
+<target>Tidsrom</target>
+
+<source>File size</source>
+<target>Filstørrelse</target>
+
+<source>Minimum</source>
+<target>Minimum</target>
+
+<source>Maximum</source>
+<target>Maksimum</target>
+
+<source>&Default</source>
+<target>&Standard</target>
+
+<source>Transactional file copy</source>
+<target>Transaksjonell filkopiering</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>Skriv til en midlertidig fil (*.ffs_tmp) først så endre navn på den. Dette garanterer en konsistent tilstand selv ved alvorlige feil.</target>
+
+<source>Copy locked files</source>
+<target>Kopier låste filer</target>
+
+<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
+<target>Kopier delte eller låste filer ved å bruke Volume Shadow Copy Service (Krever administratorrettigheter)</target>
+
+<source>Copy file access permissions</source>
+<target>Kopier filadgangstillatelser</target>
+
+<source>Transfer file and directory permissions (Requires Administrator rights)</source>
+<target>Overfør fil- og mappetillatelser (Krever administratorrettigheter)</target>
+
+<source>Restore hidden dialogs</source>
+<target>Gjenopprett skjulte dialoger</target>
+
+<source>External applications</source>
+<target>Eksterne programmer</target>
+
+<source>Description</source>
+<target>Beskrivelse</target>
+
+<source>Variant</source>
+<target>Variant</target>
+
+<source>Statistics</source>
+<target>Statistikk</target>
+
+<source>Find what:</source>
+<target>Søk hva:</target>
+
+<source>Match case</source>
+<target>Skill mellom store og små bokstaver</target>
+
+<source>&Find next</source>
+<target>&Søk neste</target>
+
+<source>Operation aborted!</source>
+<target>Handling avbrutt!</target>
+
+<source>Main bar</source>
+<target>Hovedverktøylinje</target>
+
+<source>Folder pairs</source>
+<target>Mappepar</target>
+
+<source>Overview</source>
+<target>Oversikt</target>
+
+<source>Select view</source>
+<target>Velg visning</target>
+
+<source>Set direction:</source>
+<target>Still inn retningen:</target>
+
+<source>Exclude temporarily</source>
+<target>Ekskluder midlertidig</target>
+
+<source>Include temporarily</source>
+<target>Inkluder midlertidig</target>
+
+<source>Exclude via filter:</source>
+<target>Ekskluder via filter:</target>
+
+<source><multiple selection></source>
+<target><flervalg></target>
+
+<source>Delete</source>
+<target>Slett</target>
+
+<source>Include all</source>
+<target>Inkluder alle</target>
+
+<source>Exclude all</source>
+<target>Ekskluder alle</target>
+
+<source>Show icons:</source>
+<target>Vis ikoner:</target>
+
+<source>Small</source>
+<target>Små</target>
+
+<source>Medium</source>
+<target>Middels</target>
+
+<source>Large</source>
+<target>Store</target>
+
+<source>Select time span...</source>
+<target>Velg tidsområde...</target>
+
+<source>Default view</source>
+<target>Standardvisning</target>
+
+<source>Show "%x"</source>
+<target>Vis "%x"</target>
+
+<source><Last session></source>
+<target><Siste økt></target>
+
+<source>Configuration saved!</source>
+<target>Innstilling lagret!</target>
+
+<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>Configuration loaded!</source>
+<target>Innstilling lastet!</target>
+
+<source>Folder Comparison and Synchronization</source>
+<target>Mappesammenligning og synkronisering</target>
+
+<source>Hide files that exist on left side only</source>
+<target>Skjul filer som bare finnes på venstre side</target>
+
+<source>Show files that exist on left side only</source>
+<target>Vis filer som bare finnes på venstre side</target>
+
+<source>Hide files that exist on right side only</source>
+<target>Skjul filer som bare finnes på høyre side</target>
+
+<source>Show files that exist on right side only</source>
+<target>Vis filer som bare finnes på høyre side</target>
+
+<source>Hide files that are newer on left</source>
+<target>Skjul filer som er nyere til venstre</target>
+
+<source>Show files that are newer on left</source>
+<target>Vis filer som er nyere til venstre</target>
+
+<source>Hide files that are newer on right</source>
+<target>Skjul filer som er nyere til høyre</target>
+
+<source>Show files that are newer on right</source>
+<target>Vis filer som er nyere til høyre</target>
+
+<source>Hide files that are equal</source>
+<target>Skjul filer som er like</target>
+
+<source>Show files that are equal</source>
+<target>Vis filer som er like</target>
+
+<source>Hide files that are different</source>
+<target>Skjul filer som er forskjellige</target>
+
+<source>Show files that are different</source>
+<target>Vis filer som er forskjellige</target>
+
+<source>Hide conflicts</source>
+<target>Skjul konflikter</target>
+
+<source>Show conflicts</source>
+<target>Vis konflikter</target>
+
+<source>Hide files that will be created on the left side</source>
+<target>Skjul filer som blir opprettet på venstre side</target>
+
+<source>Show files that will be created on the left side</source>
+<target>Vis filer som blir opprettet på venstre side</target>
+
+<source>Hide files that will be created on the right side</source>
+<target>Skjul filer som blir opprettet på høyre side</target>
+
+<source>Show files that will be created on the right side</source>
+<target>Vis filer som blir opprettet på høyre side</target>
+
+<source>Hide files that will be deleted on the left side</source>
+<target>Skjul filer som blir slettet på venstre side</target>
+
+<source>Show files that will be deleted on the left side</source>
+<target>Vis filer som blir slettet på venstre side</target>
+
+<source>Hide files that will be deleted on the right side</source>
+<target>Skjul filer som blir slettet på høyre side</target>
+
+<source>Show files that will be deleted on the right side</source>
+<target>Vis filer som blir slettet på høyre side</target>
+
+<source>Hide files that will be overwritten on left side</source>
+<target>Skjul filer som blir overskrevet på venstre side</target>
+
+<source>Show files that will be overwritten on left side</source>
+<target>Vis filer som blir overskrevet på venstre side</target>
+
+<source>Hide files that will be overwritten on right side</source>
+<target>Skjul filer som blir overskrevet på høyre side</target>
+
+<source>Show files that will be overwritten on right side</source>
+<target>Vis filer som blir overskrevet på høyre side</target>
+
+<source>Hide files that won't be copied</source>
+<target>Skjul filer som ikke blir kopiert</target>
+
+<source>Show files that won't be copied</source>
+<target>Vis filer som ikke blir kopiert</target>
+
+<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>
+
+<source>Legend</source>
+<target>Forklaring</target>
+
+<source>File list exported!</source>
+<target>Filliste eksportert!</target>
+
+<source>
+<pluralform>Object deleted successfully!</pluralform>
+<pluralform>%x objects deleted successfully!</pluralform>
+</source>
+<target>
+<pluralform>Objekt vellykket slettet!</pluralform>
+<pluralform>%x objekter vellykket slettet!</pluralform>
+</target>
+
+<source>
+<pluralform>1 directory</pluralform>
+<pluralform>%x directories</pluralform>
+</source>
+<target>
+<pluralform>1 mappe</pluralform>
+<pluralform>%x mapper</pluralform>
+</target>
+
+<source>
+<pluralform>1 file</pluralform>
+<pluralform>%x files</pluralform>
+</source>
+<target>
+<pluralform>1 fil</pluralform>
+<pluralform>%x filer</pluralform>
+</target>
+
+<source>
+<pluralform>%x of 1 row in view</pluralform>
+<pluralform>%x of %y rows in view</pluralform>
+</source>
+<target>
+<pluralform>%x av 1 rekke</pluralform>
+<pluralform>%x av %y rekker</pluralform>
+</target>
+
+<source>Scanning...</source>
+<target>Skanner...</target>
+
+<source>Comparing content...</source>
+<target>Sammenligner innhold...</target>
+
+<source>Paused</source>
+<target>Pauset</target>
+
+<source>Initializing...</source>
+<target>Initialiserer...</target>
+
+<source>Aborted</source>
+<target>Avbrutt</target>
+
+<source>Completed</source>
+<target>Fullført</target>
+
+<source>Continue</source>
+<target>Fortsett</target>
+
+<source>Pause</source>
+<target>Pause</target>
+
+<source>Cannot find %x</source>
+<target>Kan ikke finne %x</target>
+
+<source>Inactive</source>
+<target>Inaktiv</target>
+
+<source>Today</source>
+<target>Idag</target>
+
+<source>This week</source>
+<target>Denne uke</target>
+
+<source>This month</source>
+<target>Denne måned</target>
+
+<source>This year</source>
+<target>Dette år</target>
+
+<source>Last x days</source>
+<target>Siste x dager</target>
+
+<source>Byte</source>
+<target>Byte</target>
+
+<source>KB</source>
+<target>KB</target>
+
+<source>MB</source>
+<target>MB</target>
+
+<source>Filter</source>
+<target>Filter</target>
+
+<source>Direct</source>
+<target>Direkte</target>
+
+<source>Follow</source>
+<target>Følg</target>
+
+<source>Copy NTFS permissions</source>
+<target>Kopier NTFS-tillatelser</target>
+
+<source>Integrate external applications into context menu. The following macros are available:</source>
+<target>Integrer eksterne programmer i høyreklikkmeny. Følgende makroer er tilgjengelige:</target>
+
+<source>- full file or directory name</source>
+<target>- fullt fil- eller mappenavn</target>
+
+<source>- directory part only</source>
+<target>- bare mappedel</target>
+
+<source>- Other side's counterpart to %name</source>
+<target>- Andre sides motstykke til %name</target>
+
+<source>- Other side's counterpart to %dir</source>
+<target>- Andre sides motstykke til %dir</target>
+
+<source>Make hidden dialogs and warning messages visible again?</source>
+<target>Gjøre skjulte dialoger og advarselsmeldinger synlige igjen?</target>
+
+<source>
+<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
+<pluralform>Do you really want to move the following %x objects to the Recycle Bin?</pluralform>
+</source>
+<target>
+<pluralform>Vil du flytte det følgende objektet til papirkurven?</pluralform>
+<pluralform>Vil du flytte de følgende %x objekter til papirkurven?</pluralform>
+</target>
+
+<source>
+<pluralform>Do you really want to delete the following object?</pluralform>
+<pluralform>Do you really want to delete the following %x objects?</pluralform>
+</source>
+<target>
+<pluralform>Vil du slette det følgende objektet?</pluralform>
+<pluralform>Vil du slette de følgende %x objekter?</pluralform>
+</target>
+
+<source>Leave as unresolved conflict</source>
+<target>Etterlat som uløste konflikter</target>
+
+<source>Delete permanently</source>
+<target>Slett permanent</target>
+
+<source>Delete or overwrite files permanently</source>
+<target>Slett eller overskriv filer permanent</target>
+
+<source>Use Recycle Bin when deleting or overwriting files</source>
+<target>Bruk papirkurv ved sletting eller filoverskrivning</target>
+
+<source>Versioning</source>
+<target>Versjonshåndtering</target>
+
+<source>Move files into a time-stamped subdirectory</source>
+<target>Flytt filer til en datomerket undermappe</target>
+
+<source>Files</source>
+<target>Filer</target>
+
+<source>Percentage</source>
+<target>Prosent</target>
+
+<source>%x TB</source>
+<target>%x TB</target>
+
+<source>%x PB</source>
+<target>%x PB</target>
+
+<source>%x%</source>
+<target>%x%</target>
+
+<source>
+<pluralform>1 min</pluralform>
+<pluralform>%x min</pluralform>
+</source>
+<target>
+<pluralform>1 min</pluralform>
+<pluralform>%x min</pluralform>
+</target>
+
+<source>
+<pluralform>1 hour</pluralform>
+<pluralform>%x hours</pluralform>
+</source>
+<target>
+<pluralform>1 time</pluralform>
+<pluralform>%x timer</pluralform>
+</target>
+
+<source>
+<pluralform>1 day</pluralform>
+<pluralform>%x days</pluralform>
+</source>
+<target>
+<pluralform>1 dag</pluralform>
+<pluralform>%x dager</pluralform>
+</target>
+
+<source>Cannot monitor directory %x.</source>
+<target>Kan ikke overvåke mappen %x.</target>
+
+<source>Conversion error:</source>
+<target>Konverteringsfeil:</target>
+
+<source>Cannot delete file %x.</source>
+<target>Kan ikke slette filen %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Filen er låst av en annen prosess:</target>
+
+<source>Cannot move file %x to %y.</source>
+<target>Kan ikke flytte filen %x til %y.</target>
+
+<source>Cannot delete directory %x.</source>
+<target>Kan ikke slette mappen %x.</target>
+
+<source>Cannot write modification time of %x.</source>
+<target>Kan ikke skrive endringstid til %x.</target>
+
+<source>Cannot find system function %x.</source>
+<target>Kan ikke finne systemfunksjonen %x.</target>
+
+<source>Cannot read security context of %x.</source>
+<target>Kan ikke lese sikkerhetskontekst til %x.</target>
+
+<source>Cannot write security context of %x.</source>
+<target>Kan ikke skrive sikkerhetskontekst til %x.</target>
+
+<source>Cannot read permissions of %x.</source>
+<target>Kan ikke lese tillatelser til %x.</target>
+
+<source>Cannot write permissions of %x.</source>
+<target>Kan ikke skrive tillatelser til %x.</target>
+
+<source>Cannot create directory %x.</source>
+<target>Kan ikke opprette mappen %x.</target>
+
+<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>
+
+<source>Cannot read directory %x.</source>
+<target>Kan ikke lese mappen %x.</target>
+
+<source>Endless loop.</source>
+<target>Endeløs sløyfe.</target>
+
+<source>Cannot set privilege %x.</source>
+<target>Kan ikke sette privilegie %x.</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ikke i stand til å flytte %x til papirkurven!</target>
+
+<source>Both sides have changed since last synchronization!</source>
+<target>Begge sider er endret siden siste synkronisering!</target>
+
+<source>Cannot determine sync-direction:</source>
+<target>Kan ikke bestemme synkroniseringsretning:</target>
+
+<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>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>
+
+<source>The file does not contain a valid configuration:</source>
+<target>Filen inneholder ingen gyldig innstilling:</target>
+
+<source>You can ignore this error to consider the directory as empty.</source>
+<target>Du kan ignorere denne feil og anse mappen som tom.</target>
+
+<source>Cannot find directory %x.</source>
+<target>Kan ikke finne mappen %x.</target>
+
+<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
+<target>Mapper er avhengige av hverandre! Vær forsiktig når du setter opp synkroniseringsregler:</target>
+
+<source>Preparing synchronization...</source>
+<target>Forbereder synkronisering...</target>
+
+<source>Conflict detected:</source>
+<target>Konflikt oppdaget:</target>
+
+<source>File %x has an invalid date!</source>
+<target>Filen %x har en ugyldig dato!</target>
+
+<source>Files %x have the same date but a different size!</source>
+<target>Filer %x har den samme datoen, men forskjellig størrelse!</target>
+
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Symbolske lenker %x har den samme datoen, men forskjellige mål.</target>
+
+<source>Comparing content of files %x</source>
+<target>Sammenligner innhold til filer %x</target>
+
+<source>Comparing files by content failed.</source>
+<target>Sammenligning av filer etter innhold feilet.</target>
+
+<source>Generating file list...</source>
+<target>Lager filliste...</target>
+
+<source>Both sides are equal</source>
+<target>Begge sider er like</target>
+
+<source>Files/folders differ in attributes only</source>
+<target>Filer/mapper skiller bare i attributter</target>
+
+<source>Copy new file/folder to left</source>
+<target>Kopier ny fil/mappe til venstre</target>
+
+<source>Copy new file/folder to right</source>
+<target>Kopier ny fil/mappe til høyre</target>
+
+<source>Delete left file/folder</source>
+<target>Slett venstre fil/mappe</target>
+
+<source>Delete right file/folder</source>
+<target>Slett høyre fil/mappe</target>
+
+<source>Move file on left</source>
+<target>Flytt venstre fil</target>
+
+<source>Move file on right</source>
+<target>Flytt høyre fil</target>
+
+<source>Overwrite left file/folder with right one</source>
+<target>Overskriv venstre fil/mappe med den til høyre</target>
+
+<source>Overwrite right file/folder with left one</source>
+<target>Overskriv høyre fil/mappe med den til venstre</target>
+
+<source>Do nothing</source>
+<target>Ikke gjør noe</target>
+
+<source>Copy file attributes only to left</source>
+<target>Kopier filattributter bare til venstre</target>
+
+<source>Copy file attributes only to right</source>
+<target>Kopier filattributter bare til høyre</target>
+
+<source>Multiple...</source>
+<target>Flere...</target>
+
+<source>Deleting file %x</source>
+<target>Sletter fil %x</target>
+
+<source>Deleting folder %x</source>
+<target>Sletter mappe %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Sletter symbolsk lenke %x</target>
+
+<source>Moving file %x to recycle bin</source>
+<target>Flytter fil %x til papirkurv</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>Flytter mappe %x til papirkurv</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>Flytter symbolsk lenke %x til papirkurv</target>
+
+<source>Moving file %x to %y</source>
+<target>Flytter fil %x til %y</target>
+
+<source>Moving folder %x to %y</source>
+<target>Flytter mappe %x til %y</target>
+
+<source>Moving symbolic link %x to %y</source>
+<target>Flytter symbolsk lenke %x til %y</target>
+
+<source>Creating file %x</source>
+<target>Oppretter fil %x</target>
+
+<source>Creating symbolic link %x</source>
+<target>Oppretter symbolsk lenke %x</target>
+
+<source>Creating folder %x</source>
+<target>Oppretter mappe %x</target>
+
+<source>Overwriting file %x</source>
+<target>Overskriver fil %x</target>
+
+<source>Overwriting symbolic link %x</source>
+<target>Overskriver symbolsk lenke %x</target>
+
+<source>Verifying file %x</source>
+<target>Verifiserer fil %x</target>
+
+<source>Updating attributes of %x</source>
+<target>Oppdaterer attributter til %x</target>
+
+<source>Target directory name must not be empty!</source>
+<target>Navn på målmappe må ikke være tomt!</target>
+
+<source>Directory for file versioning was not supplied!</source>
+<target>Mappe for filversjonshåndtering ble ikke angitt!</target>
+
+<source>Source directory %x not found.</source>
+<target>Kildemappen %x ikke funnet.</target>
+
+<source>Unresolved conflicts existing!</source>
+<target>Uløste konflikter finnes!</target>
+
+<source>You can ignore conflicts and continue synchronization.</source>
+<target>Du kan ignorere konflikter og fortsette synkronisering.</target>
+
+<source>Significant difference detected:</source>
+<target>Betydelig forskjell oppdaget:</target>
+
+<source>More than 50% of the total number of files will be copied or deleted!</source>
+<target>Mer enn 50% av det totale antall filer blir kopiert eller slettet!</target>
+
+<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>Free disk space available:</source>
+<target>Ledig diskplass tilgjengelig:</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>
+
+<source>A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!</source>
+<target>En mappe blir endret som er del av flere mappepar! Kontroller synkroniseringsinnstillinger!</target>
+
+<source>Processing folder pair:</source>
+<target>Behandler mappepar:</target>
+
+<source>Generating database...</source>
+<target>Oppretter database...</target>
+
+<source>Data verification error: Source and target file have different content!</source>
+<target>Dataverifiseringsfeil: Kilde- og målfil har forskjellig innhold!</target>
+
diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng
index 44381d46..74d572c5 100644
--- a/BUILD/Languages/polish.lng
+++ b/BUILD/Languages/polish.lng
@@ -11,7 +11,7 @@
<target>Szukanie katalogu %x...</target>
<source>Show in Explorer</source>
-<target>Wyświetl w Exlporerze</target>
+<target>Wyświetl w Explorerze</target>
<source>Open with default application</source>
<target>Otwórz za pomocą domyślnej aplikacji</target>
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>PrzeglÄ…daj katalog</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Żądanie przerwania: Czekaj na koniec aktualnie wykonywanego zadania...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatyczna Synchronizacja</target>
+<source>Error</source>
+<target>BÅ‚Ä…d</target>
+
<source>Select alternate comparison settings</source>
<target>Określ alternatywne ustawienia porównywania</target>
@@ -52,11 +58,8 @@
<source>About</source>
<target>O Programie</target>
-<source>Error</source>
-<target>BÅ‚Ä…d</target>
-
<source>Warning</source>
-<target>Ostrzerzenie</target>
+<target>Ostrzeżenie</target>
<source>Question</source>
<target>Pytanie</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>BÅ‚Ä…d systemu linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>BÅ‚Ä…d odczytu dowiÄ…zania symbolicznego:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Nie można określić położenia dowiązania symbolicznego %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -137,35 +140,41 @@
<pluralform>%x Bajtów</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>BÅ‚Ä…d odczytu z bazy danych synchronizacji:</target>
+<source>Cannot read file %x.</source>
+<target>Nie można odczytać pliku %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>BÅ‚Ä…d zapisu do bazy danych synchronizacji:</target>
+<source>Cannot write file %x.</source>
+<target>Nie można zapisać pliku %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Niepoprawny format bazy danych dla synchronizacji:</target>
+<source>Database file %x is incompatible.</source>
+<target>Plika bazy danych %x nie jest kompatybilny.</target>
<source>Initial synchronization:</source>
<target>Wstępna synchronizacja:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Jeden z plików bazy danych FreeFileSync nie istnieje:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Plik bazy danych %x nie istnieje.</target>
+
+<source>Out of memory!</source>
+<target>Brak wolnej pamięci!</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Pliki danych nie współdzielą wspólnej sesji synchronizacji:</target>
+<source>Database files do not share a common session.</source>
+<target>Pliki bazy danych nie współdzielą sesji.</target>
<source>An exception occurred!</source>
<target>Wystąpił wyjątek!</target>
-<source>Error reading file attributes:</source>
-<target>Błąd odczytu atrybutów pliku:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Nie można odczytać atrybutów pliku %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Nie można uzyskać informacji dla procesu.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Blokada katalogu (%x), oczekiwanie...</target>
-<source>Error setting directory lock:</source>
-<target>BÅ‚Ä…d ustawiania blokady katalogu:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Nie można zablokować katalogu %x do zapisu.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x sekund</pluralform>
</target>
-<source>Error reading file:</source>
-<target>BÅ‚Ä…d odczytu pliku:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>BÅ‚Ä…d podczas parsowania pliku %x, rzÄ…d %y, kolumna %z.</target>
<source>Scanning:</source>
<target>Skanowanie:</target>
@@ -196,41 +205,35 @@
<pluralform>[%x Wątków]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Nieprawidłowy plik konfiguracyjny!</target>
-
-<source>Error parsing configuration file:</source>
-<target>BÅ‚Ä…d parsowania pliku konfiguracyjnego:</target>
+<source>/sec</source>
+<target>/sekundÄ™</target>
-<source>Configuration loaded partially only:</source>
-<target></target>
+<source>File %x does not contain a valid configuration.</source>
+<target>Plik %x nie zawiera prawidłowej konfiguracji</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target></target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Plik konfiguracyjny %x wczytany tylko częściowo.</target>
-<source>Cannot load file %x.</source>
-<target></target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Nie można uzyskać dostępu do usługi Volume Shadow Copy.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Błąd podczas dostępdu do usługi Volume Shadow Copy!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Usługa shadow copy jest aktywna tylko w wersji 64 bitowej programu FreeFileSync.</target>
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Tworzenie Shadow Copies dla WOW64 nie jest obsługiwane. Zainstaluj 64 bitową wersję FreeFileSync.</target>
+<source>Cannot load file %x.</source>
+<target>Nie można wczytać pliku %x.</target>
-<source>Cannot determine volume name for file:</source>
-<target></target>
+<source>Path %x does not contain a volume name.</source>
+<target>Ścieżka %x nie zawiera poprawnej etykiety dysku.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Dysk %x nie jest częścią pliku %y!</target>
-<source>/sec</source>
-<target>/sekundÄ™</target>
-
-<source>File does not exist:</source>
-<target>Plik nie istnieje:</target>
+<source>Cannot find file %x.</source>
+<target>Nie można znaleźć pliku %x.</target>
<source>Cannot read the following XML elements:</source>
-<target></target>
+<target>Nie można odczytać elementu XML:</target>
<source>S&ave configuration...</source>
<target>Z&apisz konfiguracjÄ™...</target>
@@ -271,7 +274,7 @@ The command line is executed each time:
- files within these directories or subdirectories are modified
</source>
<target>
-Komenda jest wykonwywana za każdym razem gdy:
+Komenda jest wykonywana za każdym razem gdy:
- wszystkie katalogi będą dostępne (np. włożenie USB)
- pliki w obrębie tych katalogów i podkatalogów ulegną zmianie
</target>
@@ -295,19 +298,22 @@ Komenda jest wykonwywana za każdym razem gdy:
<target>Minimalny czas bezczynności [sekundy]</target>
<source>Idle time between detection of last change and execution of command line in seconds</source>
-<target>Odstęp czasu w sekundach pomiędzy pomiędzy ostatnią wykrytą zmianą, a wykonaniem komendy</target>
+<target>Odstęp czasu w sekundach pomiędzy ostatnią wykrytą zmianą, a wykonaniem komendy</target>
<source>Start</source>
<target>Rozpocznij</target>
+<source>&Retry</source>
+<target>&Powtórz</target>
+
+<source>Cancel</source>
+<target>Anuluj</target>
+
<source>(Build: %x)</source>
<target>(Zbudowano: %x)</target>
<source>RealtimeSync configuration</source>
-<target>RealtimeSync konfiguracja</target>
-
-<source>File already exists. Overwrite?</source>
-<target>Nadpisać istniejący już plik?</target>
+<target>Konfiguracja RealtimeSync</target>
<source>&Restore</source>
<target>&Przywróć</target>
@@ -346,40 +352,43 @@ Komenda jest wykonwywana za każdym razem gdy:
<target>WÅ‚asne</target>
<source>FreeFileSync batch file</source>
-<target>FreeFileSync plik wsadowy</target>
+<target>Plik wsadowy FreeFileSync</target>
<source>FreeFileSync configuration</source>
<target>Konfiguracja FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync plik wsadowy</target>
-
-<source>Unable to create log file!</source>
-<target>Nie można utworzyć pliku z logami!</target>
-
<source>Batch execution</source>
<target>Uruchomienie pliku wsadowego</target>
-<source>Stop</source>
-<target>Zatrzymaj</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>
+<source>Nothing to synchronize!</source>
+<target>Brak plików do synchronizacji!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synchronizacja zakończona pomyślnie!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Naciśnij "Przełącz" aby otworzyć moduł GUI.</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>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Przełączanie do trybu GUI FreeFileSync</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Przełączanie do głównego okna FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Nie można się połączyć z sourceforge.net!</target>
@@ -394,7 +403,7 @@ Komenda jest wykonwywana za każdym razem gdy:
<target>Informacja</target>
<source>FreeFileSync is up to date!</source>
-<target>FreeFileSync jest już uaktualniony!</target>
+<target>Posiadasz aktualnÄ… wersjÄ™ FreeFileSync!</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Czy chcesz aby FreeFileSync sprawdzał uaktualnienia co tydzień?</target>
@@ -409,7 +418,7 @@ Komenda jest wykonwywana za każdym razem gdy:
<target><Katalog></target>
<source>Full path</source>
-<target>Pełna scieżka</target>
+<target>Pełna ścieżka</target>
<source>Name</source>
<target>Nazwa</target>
@@ -537,9 +546,6 @@ Komenda jest wykonwywana za każdym razem gdy:
<source>Items found:</source>
<target>Znalezione elementy:</target>
-<source>Items remaining:</source>
-<target>Pozostałe elementy:</target>
-
<source>Speed:</source>
<target>Prędkość:</target>
@@ -553,7 +559,7 @@ Komenda jest wykonwywana za każdym razem gdy:
<target>Plik wsadowy</target>
<source>Create a batch file and automate synchronization. To start in batch mode simply double-click this file or run command: FreeFileSync.exe SyncJob.ffs_batch. This can also be scheduled in your system's task planner.</source>
-<target></target>
+<target>Utwórz plik wsadowy aby zautomatyzować proces synchronizacji. Aby uruchomić synchronizację w trybie wsadowym kliknij dwa razy kliknij na ten plik lub wykonaj komendę: FreeFileSync.exe SyncJob.ffs_batch. Możesz to również wykorzystać w swoim harmonogramie zadań.</target>
<source>Help</source>
<target>Pomoc</target>
@@ -567,9 +573,6 @@ Komenda jest wykonwywana za każdym razem gdy:
<source>Right</source>
<target>Prawy</target>
-<source>Sync setttings</source>
-<target></target>
-
<source>Status feedback</source>
<target>Opinia statusu</target>
@@ -594,9 +597,6 @@ Komenda jest wykonwywana za każdym razem gdy:
<source>&Load</source>
<target>&Wczytaj</target>
-<source>&Cancel</source>
-<target>&Anuluj</target>
-
<source>Select variant:</source>
<target>Wybierz wariant:</target>
@@ -645,8 +645,8 @@ Komenda jest wykonwywana za każdym razem gdy:
<source>Conflict/file cannot be categorized</source>
<target>Konflikt/plik nie może zostać skategoryzowany</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Porównaj przez...</target>
@@ -681,9 +681,6 @@ jest identyczna
<source>Synchronizing...</source>
<target>SynchronizujÄ™...</target>
-<source>Items processed:</source>
-<target>Przetworzeone elementy:</target>
-
<source>&Pause</source>
<target>&Pauza</target>
@@ -715,7 +712,7 @@ jest identyczna
<target>Udostępnione na zasadach licencji GNU General Public License</target>
<source>Ignore further errors</source>
-<target></target>
+<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>
@@ -723,9 +720,6 @@ jest identyczna
<source>&Ignore</source>
<target>&Ignoruj</target>
-<source>&Retry</source>
-<target>&Powtórz</target>
-
<source>Do not show this dialog again</source>
<target>Nie pokazuj tego okna ponownie</target>
@@ -751,13 +745,16 @@ jest identyczna
Only files that match all filter settings will be synchronized.
Note: File names must be relative to base directories!
</source>
-<target></target>
+<target>
+Tylko pliki pasujące do wszystkich filtrów będą synchronizowane.
+Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowego.
+</target>
<source>Hints:</source>
<target>Wskazówki:</target>
<source>1. Enter relative file or directory names separated by ';' or a new line.</source>
-<target>1. Wprowdź relatywne scieżki do plików lub katalogów oddzielone ';' lub nową linią.</target>
+<target>1. Wprowadź relatywne scieżki do plików lub katalogów oddzielone ';' lub nową linią.</target>
<source>2. Use wildcard characters '*' and '?'.</source>
<target>2. Użyj wieloznacznika (wildcard) '*' i '?'.</target>
@@ -787,16 +784,16 @@ Wyklucz: \moje\temp\*
<target>Wyklucz</target>
<source>Time span</source>
-<target></target>
+<target>Przedział czasowy</target>
<source>File size</source>
-<target></target>
+<target>Rozmiar pliku</target>
<source>Minimum</source>
-<target></target>
+<target>Minimum</target>
<source>Maximum</source>
-<target></target>
+<target>Maksimum</target>
<source>&Default</source>
<target>&Domyślne</target>
@@ -820,7 +817,7 @@ Wyklucz: \moje\temp\*
<target>Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora)</target>
<source>Restore hidden dialogs</source>
-<target></target>
+<target>Przywróc ukryte dialogi</target>
<source>External applications</source>
<target>Aplikacje zewnętrzne</target>
@@ -883,7 +880,7 @@ Wyklucz: \moje\temp\*
<target>Odznacz wszystko</target>
<source>Show icons:</source>
-<target></target>
+<target>Pokaż ikony:</target>
<source>Small</source>
<target>Mały</target>
@@ -910,7 +907,7 @@ Wyklucz: \moje\temp\*
<target>Konfiguracja zapisana!</target>
<source>Never save changes</source>
-<target></target>
+<target>Nigdy nie zapisuj zmian</target>
<source>Save changes to current configuration?</source>
<target>Zapisać zmiany obecnej konfiguracji?</target>
@@ -1020,9 +1017,6 @@ Wyklucz: \moje\temp\*
<source>File list exported!</source>
<target>Lista plików wyeksportowana!</target>
-<source>Error writing file:</source>
-<target>BÅ‚Ä…d zapisu pliku:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1072,21 +1066,21 @@ Wyklucz: \moje\temp\*
<source>Paused</source>
<target>Pauza</target>
+<source>Initializing...</source>
+<target>Inicjalizacja...</target>
+
<source>Aborted</source>
<target>Przerwana</target>
<source>Completed</source>
<target>Zakończono</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Żądanie przerwania: Czekaj na koniec aktualnie wykonywanego zadania...</target>
+<source>Continue</source>
+<target>Kontynuuj</target>
<source>Pause</source>
<target>Pauza</target>
-<source>Continue</source>
-<target>Kontynuuj</target>
-
<source>Cannot find %x</source>
<target>Nie można znaleźć %x</target>
@@ -1106,7 +1100,7 @@ Wyklucz: \moje\temp\*
<target>W tym roku</target>
<source>Last x days</source>
-<target></target>
+<target>Ostatnie x dni</target>
<source>Byte</source>
<target>Bajtów</target>
@@ -1118,13 +1112,13 @@ Wyklucz: \moje\temp\*
<target>MB</target>
<source>Filter</source>
-<target></target>
+<target>Filtr</target>
<source>Direct</source>
<target>Bezpośrednio</target>
<source>Follow</source>
-<target>PodÄ…rzaj</target>
+<target>Podążaj</target>
<source>Copy NTFS permissions</source>
<target>Kopiuj uprawnienia NTFS</target>
@@ -1145,7 +1139,7 @@ Wyklucz: \moje\temp\*
<target>- Odpowiednik %dir</target>
<source>Make hidden dialogs and warning messages visible again?</source>
-<target></target>
+<target>Czy chcesz ponownie aktywować ukryte powiadomienia i ostrzeżenia?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1230,68 +1224,65 @@ Wyklucz: \moje\temp\*
<pluralform>%x dni</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Nie można uruchomić monitora katalogów:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Błąd podczas monitorowania katalogów.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Nie można monitorować katalogu %x.</target>
<source>Conversion error:</source>
<target>BÅ‚Ä…d konwersji:</target>
-<source>Error deleting file:</source>
-<target>BÅ‚Ä…d podczas usuwania pliku:</target>
+<source>Cannot delete file %x.</source>
+<target>Nie można usunąć pliku %x.</target>
-<source>Error moving file:</source>
-<target>BÅ‚Ä…d podczas przenoszenia pliku:</target>
+<source>The file is locked by another process:</source>
+<target>Plik jest zablokowany przez inny proces:</target>
-<source>Target file already existing!</source>
-<target>Plik docelowy już istnieje!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Nie można przenieść pliku %x do %y.</target>
-<source>Error moving directory:</source>
-<target>BÅ‚Ä…d podczas przenoszenia katalogu:</target>
+<source>Cannot delete directory %x.</source>
+<target>Nie można usunąć katalogu %x.</target>
-<source>Target directory already existing!</source>
-<target>Katalog docelowy już istnieje!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Nie można zapisać czasu modyfikacji %x.</target>
-<source>Error deleting directory:</source>
-<target>BÅ‚Ä…d podczas usuwania katalogu:</target>
+<source>Cannot find system function %x.</source>
+<target>Nie można odnaleźć funkcji systemowej %x.</target>
-<source>Error changing modification time:</source>
-<target>BÅ‚Ä…d zmiany godziny modyfikacji:</target>
+<source>Cannot read security context of %x.</source>
+<target>Nie można odczytać ustawień bezpieczeństwa %x.</target>
-<source>Error loading library function:</source>
-<target>BÅ‚Ä…d wczytywania funkcji:</target>
+<source>Cannot write security context of %x.</source>
+<target>Nie można zapisać ustawień bezpieczeństwa %x.</target>
-<source>Error reading security context:</source>
-<target>Błąd odczytu kontekstu bezpieczeństwa:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Nie można odczytać uprawnień %x.</target>
-<source>Error writing security context:</source>
-<target>Błąd zapisu kontekstu bezpieczeństwa:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Nie można zapisać uprawnień %x.</target>
-<source>Error copying file permissions:</source>
-<target>Błąd podczas kopiowania uprawnień pliku:</target>
+<source>Cannot create directory %x.</source>
+<target>Nie można utworzyć katalogu %x.</target>
-<source>Error creating directory:</source>
-<target>BÅ‚Ä…d podczas tworzenia katalogu:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Nie można skopiować dowiązania symbolicznego %x do %y.</target>
-<source>Error copying symbolic link:</source>
-<target>BÅ‚Ä…d podczas kopiowania dowiÄ…zania symbolicznego (symlink)</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nie można zapisać atrybutów %x.</target>
-<source>Error copying file:</source>
-<target>BÅ‚Ä…d podczas kopiowania pliku:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Nie można skopiować pliku %x do %y.</target>
-<source>Error opening file:</source>
-<target>BÅ‚Ä…d odczytu pliku:</target>
+<source>Cannot read directory %x.</source>
+<target>Nie można odczytać katalogu %x.</target>
-<source>Error traversing directory:</source>
-<target>BÅ‚Ä…d podczas odczytywania katalogu:</target>
+<source>Endless loop.</source>
+<target>Nieskończona pętla.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Zapętlenie podczas przeglądania katalogu:</target>
+<source>Cannot set privilege %x.</source>
+<target>Nie można ustawić uprawnień %x.</target>
-<source>Error setting privilege:</source>
-<target>Błąd ustawiania uprawnień:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Nie można przenieść %x do kosza!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Obie strony uległy zmianie od ostatniej synchronizacji!</target>
@@ -1317,8 +1308,8 @@ Wyklucz: \moje\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Możesz zignorować ten błąd uznająć jeden z katalogów jako pusty.</target>
-<source>Directory does not exist:</source>
-<target>Katalog nie istnieje:</target>
+<source>Cannot find directory %x.</source>
+<target>Nie można znaleźć katalogu %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Katalogi są zależne! Pamiętaj o tym podczas ustawiania zasad synchronizacji:</target>
@@ -1326,20 +1317,17 @@ Wyklucz: \moje\temp\*
<source>Preparing synchronization...</source>
<target>Przygotowywanie synchronizacji...</target>
-<source>Out of memory!</source>
-<target></target>
+<source>Conflict detected:</source>
+<target>Wykryto konflikt:</target>
<source>File %x has an invalid date!</source>
<target>Plik %x ma nieprawidłową datę!</target>
-<source>Conflict detected:</source>
-<target>Wykryto konflikt:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Pliki %x mają tą samą datę lecz różne rozmiary!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>DowiÄ…zanie symboliczne %x ma te same dane, ale inny cel!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Dowiązania symboliczne %x mają tą samą datę, ale różne źródła.</target>
<source>Comparing content of files %x</source>
<target>Porównywanie zawartości plików %x</target>
@@ -1422,12 +1410,12 @@ Wyklucz: \moje\temp\*
<source>Creating file %x</source>
<target>Tworzenie pliku %x</target>
-<source>Creating folder %x</source>
-<target>Tworzenie folderu %x</target>
-
<source>Creating symbolic link %x</source>
<target>Tworzenie dowiÄ…zania symbolicznego %x</target>
+<source>Creating folder %x</source>
+<target>Tworzenie folderu %x</target>
+
<source>Overwriting file %x</source>
<target>Nadpisywanie pliku %x</target>
@@ -1446,8 +1434,8 @@ Wyklucz: \moje\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Nie określono katalogu do wersjonowania plików!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Katalog źródłowy nie istnieje:</target>
+<source>Source directory %x not found.</source>
+<target>Katalog źródłowy %x nie istnieje.</target>
<source>Unresolved conflicts existing!</source>
<target>IstniejÄ… nierozwiÄ…zane konflikty!</target>
@@ -1482,12 +1470,6 @@ Wyklucz: \moje\temp\*
<source>Generating database...</source>
<target>Generowanie bazy danych...</target>
-<source>Nothing to synchronize!</source>
-<target></target>
-
-<source>Unable to copy locked file %x!</source>
-<target></target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Błąd weryfikacji danych: Plik źródłowy i docelowy różnią się zawartością!</target>
diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng
index 3bbf2d40..a3a07ba4 100644
--- a/BUILD/Languages/portuguese.lng
+++ b/BUILD/Languages/portuguese.lng
@@ -19,8 +19,11 @@
<source>Browse directory</source>
<target>Procurar directório</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Abortar pedido: À espera do fim da operação atual...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
-<target>RealtimeSync - Sincronização Automática</target>
+<target>RealtimeSync - Sincronização Automatizada</target>
<source>Select alternate comparison settings</source>
<target>Selecionar opções alternativas de comparação</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Código de erro do Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Erro na resolução do link simbólico:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Não é possível resolver o link simbólico %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Erro ao ler a base de dados de sincronização:</target>
+<source>Cannot read file %x.</source>
+<target>Não é possível ler o ficheiro %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Erro na escrita da base de dados de sincronização:</target>
+<source>Cannot write file %x.</source>
+<target>Não é possível escrever o ficheiro %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Formato de base de dados de sincronização incompatível:</target>
+<source>Database file %x is incompatible.</source>
+<target>Base de dados %x não é compatível.</target>
<source>Initial synchronization:</source>
<target>Sincronização inicial:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Um dos ficheiros da base de dados não existe:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Base de dados %x não existe.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Bases de dados não partilham a mesma sessão de sincronização:</target>
+<source>Out of memory!</source>
+<target>Sem memória disponível!</target>
+
+<source>Database files do not share a common session.</source>
+<target>As bases de dados são de sessões diferentes.</target>
<source>An exception occurred!</source>
<target>Ocorreu uma excepção!</target>
-<source>Error reading file attributes:</source>
-<target>Erro ao ler atributos do ficheiro:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Não é possível ler os atributos do ficheiro %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Não é possível obter informação sobre o processo.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Aguardar enquanto o directório é bloqueado (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Erro ao bloquear directório:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Não é possível bloquear o directório %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x segs</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Erro de leitura de ficheiro:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Erro ao analisar ficheiro %x, linha %y, coluna %z.</target>
<source>Scanning:</source>
<target>A pesquisar:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Ficheiro de configuração inválido!</target>
+<source>/sec</source>
+<target>/seg</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Ficheiro %x não tem uma configuração válida.</target>
-<source>Error parsing configuration file:</source>
-<target>Erro de leitura do ficheiro de configuração:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Ficheiro de configuração %x carregado parcialmente.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configuração carregada parcialmente:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Não é possível aceder ao serviço Volume Shadow Copy.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Não é possível mover %x para a Reciclagem!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Utilize a versão 64-bit do FreeFileSync para criar cópias sombra neste sistema.</target>
<source>Cannot load file %x.</source>
<target>Não é possível carregar o ficheiro %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Erro no acesso ao serviço Volume Shadow Copy!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Fazer cópias fantasma em WOW64 não é suportado. Por favor usar a versão 64-bit.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Não é possível obter o nome do volume para o ficheiro:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>O caminho %x não tem um nome de volume.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Nome do volume %x não faz parte do ficheiro %y!</target>
-<source>/sec</source>
-<target>/seg</target>
-
-<source>File does not exist:</source>
-<target>O ficheiro não existe:</target>
+<source>Cannot find file %x.</source>
+<target>Não é possível encontrar o ficheiro %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Não é possível ler os elementos XML:</target>
@@ -257,10 +260,10 @@
<target>1. Selecionar directórios a monitorizar.</target>
<source>2. Enter a command line.</source>
-<target>2. Insirir a linha de comando.</target>
+<target>2. Inserir a linha de comando.</target>
<source>3. Press 'Start'.</source>
-<target>3. Pressione 'Iniciar'.</target>
+<target>3. Pressionar 'Iniciar'.</target>
<source>
The command line is executed each time:
@@ -303,9 +306,6 @@ A linha de comandos é executada cada vez que:
<source>RealtimeSync configuration</source>
<target>Configuração do RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>O ficheiro já existe. Deseja substituir?</target>
-
<source>&Restore</source>
<target>&Restaurar</target>
@@ -316,7 +316,7 @@ A linha de comandos é executada cada vez que:
<target>Monitorizar activado...</target>
<source>Waiting for missing directories...</source>
-<target>Aguardar pelos directórios em falta...</target>
+<target>A aguardar pelos directórios em falta...</target>
<source>A directory input field is empty.</source>
<target>Um campo de directório está vazio.</target>
@@ -348,35 +348,38 @@ A linha de comandos é executada cada vez que:
<source>FreeFileSync configuration</source>
<target>FreeFileSync configuração</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync ficheiro batch</target>
-
-<source>Unable to create log file!</source>
-<target>Não é possível criar ficheiro log!</target>
-
<source>Batch execution</source>
<target>Execução do batch</target>
-<source>Stop</source>
-<target>Parar</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>Synchronization aborted!</source>
<target>Sincronização abortada!</target>
<source>Synchronization completed with errors!</source>
<target>Sincronização completa com erros!</target>
+<source>Nothing to synchronize!</source>
+<target>Nada a sincronizar!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sincronização completa com sucesso!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Clique "Trocar" para abrir o GUI do FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Pressionar "Trocar" para resolver problemas com a interface principal do FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>A abrir o GUI do FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>A trocar para a interface principal do FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Não é possível ligar a sourceforge.net!</target>
@@ -502,7 +505,7 @@ A linha de comandos é executada cada vez que:
<target>Trocar lados</target>
<source>Save current configuration to file</source>
-<target>Guardar o actual ficheiro de configuração</target>
+<target>Guardar configuração actual para ficheiro</target>
<source>Load configuration from file</source>
<target>Carregar configuração do ficheiro</target>
@@ -534,9 +537,6 @@ A linha de comandos é executada cada vez que:
<source>Items found:</source>
<target>Elementos encontrados:</target>
-<source>Items remaining:</source>
-<target>Elementos restantes:</target>
-
<source>Speed:</source>
<target>Velocidade:</target>
@@ -586,16 +586,16 @@ A linha de comandos é executada cada vez que:
<target>&Guardar</target>
<source>&Load</source>
-<target>&Carregar</target>
+<target>C&arregar</target>
-<source>&Cancel</source>
-<target>&Cancelar</target>
+<source>Cancel</source>
+<target>Cancelar</target>
<source>Select variant:</source>
<target>Selecione uma variante:</target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
-<target>Identificar e propagar mudanças em ambos os lados utilizando base de dados. Eliminar, renomear e conflitos são detetados automaticamente.</target>
+<target>Identificar e propagar mudanças em ambos os lados utilizando base de dados. Itens eliminados, renomeados e conflitos são detetados automaticamente.</target>
<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
<target>Cópia de segurança do directório à esquerda. O directório da direita é alterado para ficar igual ao da esquerda após sincronização.</target>
@@ -639,8 +639,8 @@ A linha de comandos é executada cada vez que:
<source>Conflict/file cannot be categorized</source>
<target>Ficheiro/conflito não pode ser categorizado</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Comparar por...</target>
@@ -674,14 +674,11 @@ Os ficheiros são considerados iguais se
<source>Synchronizing...</source>
<target>A sincronizar...</target>
-<source>Items processed:</source>
-<target>Elementos processados:</target>
-
<source>&Pause</source>
<target>&Pausa</target>
<source>Source code written in C++ utilizing:</source>
-<target>Código fonte escrito em C++ usando:</target>
+<target>Código fonte escrito em C++ utilizando:</target>
<source>Feedback and suggestions are welcome</source>
<target>Comentários e sugestões são apreciados</target>
@@ -708,7 +705,7 @@ Os ficheiros são considerados iguais se
<target>Publicado sobre GNU General Public License</target>
<source>Ignore further errors</source>
-<target>Ignorar erros seguintes</target>
+<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>
@@ -720,7 +717,7 @@ Os ficheiros são considerados iguais se
<target>&Tentar de Novo</target>
<source>Do not show this dialog again</source>
-<target>Não mostrar novamente</target>
+<target>Não mostrar este diálogo novamente</target>
<source>&Switch</source>
<target>&Trocar</target>
@@ -753,7 +750,7 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<target>Dicas:</target>
<source>1. Enter relative file or directory names separated by ';' or a new line.</source>
-<target>1. Inserir caminho(s) do(s) ficheiro(s) ou pasta(s) separados por ';' ou numa nova linha.</target>
+<target>1. Inserir caminhos dos ficheiros ou pastas separados por ';' ou numa nova linha.</target>
<source>2. Use wildcard characters '*' and '?'.</source>
<target>2. Usar '*' e '?' como caracteres de procura.</target>
@@ -774,7 +771,7 @@ Excluir: \stuff\temp\*
</target>
<source>Synchronize all .doc, .zip and .exe files except everything in subfolder "temp".</source>
-<target>Sincronizar todos os ficheiros .doc, .zip e .exe excepto os da pasta "temp".</target>
+<target>Sincronizar todos os ficheiros .doc, .zip e .exe, excepto os da pasta "temp".</target>
<source>Include</source>
<target>Incluir</target>
@@ -798,10 +795,10 @@ Excluir: \stuff\temp\*
<target>&Config. Iniciais</target>
<source>Transactional file copy</source>
-<target>Copia ficheiro transacional</target>
+<target>Cópia de ficheiro transacional</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>Escrever para um ficheiro temporário (*.ffs_tmp) primeiro, depois renomear. Isto garante consistência mesmo em caso de erro fatal.</target>
+<target>Escrever para um ficheiro temporário (*.ffs_tmp) primeiro e depois renomear. Isto garante consistência mesmo em caso de erro fatal.</target>
<source>Copy locked files</source>
<target>Copiar ficheiros bloqueados</target>
@@ -852,7 +849,7 @@ Excluir: \stuff\temp\*
<target>Vista</target>
<source>Select view</source>
-<target>Seleccionar vista</target>
+<target>Selecionar vista</target>
<source>Set direction:</source>
<target>Escolher direcção:</target>
@@ -1008,7 +1005,7 @@ Excluir: \stuff\temp\*
<target>Use Comparar antes da primeira sincronização!</target>
<source>Comma separated list</source>
-<target>Lista de itens separados por virgulas</target>
+<target>Lista de itens separados por vírgulas</target>
<source>Legend</source>
<target>Legenda</target>
@@ -1016,9 +1013,6 @@ Excluir: \stuff\temp\*
<source>File list exported!</source>
<target>Lista dos ficheiros exportada!</target>
-<source>Error writing file:</source>
-<target>Erro de escrita no ficheiro:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1064,21 +1058,21 @@ Excluir: \stuff\temp\*
<source>Paused</source>
<target>Em pausa</target>
+<source>Initializing...</source>
+<target>A iniciar...</target>
+
<source>Aborted</source>
<target>Abortado</target>
<source>Completed</source>
<target>Terminado</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abortar pedido: À espera do fim da operação atual...</target>
+<source>Continue</source>
+<target>Continuar</target>
<source>Pause</source>
<target>Pausa</target>
-<source>Continue</source>
-<target>Continuar</target>
-
<source>Cannot find %x</source>
<target>Não é possível descobrir %x</target>
@@ -1144,8 +1138,8 @@ Excluir: \stuff\temp\*
<pluralform>Do you really want to move the following %x objects to the Recycle Bin?</pluralform>
</source>
<target>
-<pluralform>Deseja mesmo mover o seguinte objecto para a Reciclagem?</pluralform>
-<pluralform>Deseja mesmo mover os seguintes %x objectos para a Reciclagem?</pluralform>
+<pluralform>Deseja mesmo mover o objecto para a Reciclagem?</pluralform>
+<pluralform>Deseja mesmo mover os %x objectos para a Reciclagem?</pluralform>
</target>
<source>
@@ -1217,65 +1211,65 @@ Excluir: \stuff\temp\*
<pluralform>%x dias</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Não é possível iniciar monitorização do directório:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Erro ao monitorizar os directórios.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Não é possível monitorizar o directório %x.</target>
<source>Conversion error:</source>
<target>Erro de conversão:</target>
-<source>Error deleting file:</source>
-<target>Erro ao eliminar o ficheiro:</target>
+<source>Cannot delete file %x.</source>
+<target>Não é possível eliminar o ficheiro %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>O ficheiro está bloqueado por outro processo:</target>
-<source>Error moving file:</source>
-<target>Erro ao mover o ficheiro:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Não é possível mover o ficheiro %x para %y.</target>
-<source>Target file already existing!</source>
-<target>Ficheiro de destino já existe!</target>
+<source>Cannot delete directory %x.</source>
+<target>Não é possível eliminar o directório %x.</target>
-<source>Error moving directory:</source>
-<target>Erro ao mover o directório:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Não é possível alterar a data de modificação a %x.</target>
-<source>Target directory already existing!</source>
-<target>Directório de destino já existe!</target>
+<source>Cannot find system function %x.</source>
+<target>Não é possível encontrar a função do sistema %x.</target>
-<source>Error deleting directory:</source>
-<target>Erro ao eliminar a pasta:</target>
+<source>Cannot read security context of %x.</source>
+<target>Não é possível ler o contexto de segurança %x.</target>
-<source>Error changing modification time:</source>
-<target>Erro ao mudar a hora de modificação:</target>
+<source>Cannot write security context of %x.</source>
+<target>Não é possível escrever o contexto de segurança %x.</target>
-<source>Error loading library function:</source>
-<target>Erro ao carregar a livraria:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Não é possível ler as permissões de %x.</target>
-<source>Error reading security context:</source>
-<target>Erro ao ler contexto de segurança:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Não é possível escrever as permissões de %x.</target>
-<source>Error writing security context:</source>
-<target>Erro de escrita no contexto de segurança:</target>
+<source>Cannot create directory %x.</source>
+<target>Não é possível criar o directório %x.</target>
-<source>Error copying file permissions:</source>
-<target>Erro ao copiar permissões dos ficheiros:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Não é possível copiar o link simbólico %x para %y.</target>
-<source>Error creating directory:</source>
-<target>Erro ao criar a pasta:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Não é possível escrever os atributos de %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Erro ao copiar o link:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Não é possível copiar o ficheiro %x para %y.</target>
-<source>Error copying file:</source>
-<target>Erro ao copiar ficheiro:</target>
+<source>Cannot read directory %x.</source>
+<target>Não é possível ler o directório %x.</target>
-<source>Error traversing directory:</source>
-<target>Erro ao percorrer a pasta:</target>
+<source>Endless loop.</source>
+<target>Loop infinito.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Loop infinito ao percorrer directório:</target>
+<source>Cannot set privilege %x.</source>
+<target>Não é possível definir o privilégio %x.</target>
-<source>Error setting privilege:</source>
-<target>Erro ao estabelecer privilégios:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Não é possível mover %x para a Reciclagem!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Ambos os lados tiveram alterações desde a última sincronização!</target>
@@ -1284,7 +1278,7 @@ Excluir: \stuff\temp\*
<target>Não é possível saber a direção de sincronização:</target>
<source>No change since last synchronization!</source>
-<target>Não há alterações desde a sincronização!</target>
+<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>
@@ -1301,8 +1295,8 @@ Excluir: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Pode ignorar este erro para considerar o directório como vazio.</target>
-<source>Directory does not exist:</source>
-<target>A pasta não existe:</target>
+<source>Cannot find directory %x.</source>
+<target>Não é possível encontrar o directório %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Directórios são dependentes! Cuidado ao definir as regras de sincronização:</target>
@@ -1310,20 +1304,17 @@ Excluir: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>A preparar sincronização...</target>
-<source>Out of memory!</source>
-<target>Sem memória disponível!</target>
+<source>Conflict detected:</source>
+<target>Conflito detectado:</target>
<source>File %x has an invalid date!</source>
<target>Ficheiro %x tem data inválida!</target>
-<source>Conflict detected:</source>
-<target>Conflito detectado:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Os ficheiros %x têm a mesma data, mas tamanho diferente!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Links simbólicos %x tem a mesma data mas diferente destino!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Links simbólicos %x tem a mesma data, mas alvos diferentes.</target>
<source>Comparing content of files %x</source>
<target>A comparar o conteúdo do ficheiro %x</target>
@@ -1389,7 +1380,7 @@ Excluir: \stuff\temp\*
<target>Mover ficheiro %x para a Reciclagem</target>
<source>Moving folder %x to recycle bin</source>
-<target>Mover pasta %x para Reciclagem</target>
+<target>Mover pasta %x para a Reciclagem</target>
<source>Moving symbolic link %x to recycle bin</source>
<target>Mover link simbólico %x para a Reciclagem</target>
@@ -1406,12 +1397,12 @@ Excluir: \stuff\temp\*
<source>Creating file %x</source>
<target>Criar ficheiro %x</target>
-<source>Creating folder %x</source>
-<target>Criar pasta %x</target>
-
<source>Creating symbolic link %x</source>
<target>Criar link simbólico %x</target>
+<source>Creating folder %x</source>
+<target>Criar pasta %x</target>
+
<source>Overwriting file %x</source>
<target>Substituir ficheiro %x</target>
@@ -1430,8 +1421,8 @@ Excluir: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Diretório para armazenar versões não foi definido!</target>
-<source>Source directory does not exist anymore:</source>
-<target>A pasta de origem já não existe:</target>
+<source>Source directory %x not found.</source>
+<target>Directório fonte %x não encontrado.</target>
<source>Unresolved conflicts existing!</source>
<target>Existem conflitos por resolver!</target>
@@ -1455,10 +1446,10 @@ Excluir: \stuff\temp\*
<target>Espaço livre disponível em disco:</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! Ficheiros serão apagados permanentemente:</target>
+<target>Reciclagem não disponível para os seguintes caminhos! Os ficheiros serão apagados permanentemente:</target>
<source>A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!</source>
-<target>Um directório que pertencente a conjunto de vários directórios vai ser alterado! Por favor, verifique as opções de sincronização!</target>
+<target>Um directório que pertencente a um conjunto de vários directórios vai ser alterado! Verifique as opções de sincronização!</target>
<source>Processing folder pair:</source>
<target>A processar o par do directorio:</target>
@@ -1466,12 +1457,6 @@ Excluir: \stuff\temp\*
<source>Generating database...</source>
<target>A gerar base de dados...</target>
-<source>Nothing to synchronize!</source>
-<target>Nada a sincronizar!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Não é possível copiar o ficheiro bloqueado %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Erro na verificação de dados: ficheiro fonte e de destino têm conteúdo diferente!</target>
diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng
index 9d91309a..0e14cfe7 100644
--- a/BUILD/Languages/portuguese_br.lng
+++ b/BUILD/Languages/portuguese_br.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Navegar pelo diretório</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Cancelar solicitado: Esperando fim da operação...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Sincronização Automatizada</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Código de Erro do Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Erro na resolução de link simbólico:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Não foi possível resolver o link simbólico %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Erro ao ler do banco de dados de sincronização:</target>
+<source>Cannot read file %x.</source>
+<target>Não foi possível ler o arquivo %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Erro ao escrever no banco de dados de sincronização:</target>
+<source>Cannot write file %x.</source>
+<target>Não foi possível escrever o arquivo %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Formato de banco de dados de sincronização incompatível:</target>
+<source>Database file %x is incompatible.</source>
+<target>O arquivo de banco de dados %x é incompatível.</target>
<source>Initial synchronization:</source>
<target>Sincronização inicial:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Um dos arquivos de banco de dados do FreeFileSync ainda não existe:</target>
+<source>Database file %x does not yet exist.</source>
+<target>O arquivo de banco de dados %x ainda não existe.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Arquivos de banco de dados não compartilham uma sessão de sincronização comum:</target>
+<source>Out of memory!</source>
+<target>Falta de memória!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Os arquivos de banco de dados não compartilham uma sessão comum.</target>
<source>An exception occurred!</source>
<target>Ocorreu uma exceção!</target>
-<source>Error reading file attributes:</source>
-<target>Erro ao ler atributos do arquivo:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Não foi possível ler os atributos do arquivo %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Não foi possível obter as informações do processo.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Esperando enquanto o diretório é travado (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Erro ao definir bloqueio no diretório:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Não foi possível ajustar o bloqueio no diretório %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x seg</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Erro ao ler arquivo:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Erro analisando o arquivo %x, linha %y, coluna %z.</target>
<source>Scanning:</source>
<target>Pesquisando:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Threads]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Arquivo de configuração do FreeFileSync inválido!</target>
+<source>/sec</source>
+<target>/seg</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>
-<source>Error parsing configuration file:</source>
-<target>Erro de leitura do arquivo de configuração:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>O arquivo de configuração %x foi lido parcialmente apenas.</target>
-<source>Configuration loaded partially only:</source>
-<target>A configuração foi carregada parcialmente apenas:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Não foi possível acessar o Serviço Cópia de Sombra de Volume.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Não foi possível mover %x para a Lixeira!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Por favor, utilize a versão 64 bits do FreeFileSync para criar cópias de sombra neste sistema.</target>
<source>Cannot load file %x.</source>
<target>Não foi possível carregar o aquivo %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Erro ao acessar o Serviço de Cópia de Sombra de Volume!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Cópias de sombra no WOW64 não são suportadas. Por favor use a versão 64-bits do FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Não foi possível determinar o nome do volume para o arquivo:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>O caminho %x não contém um nome de volume.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Nome do volume %x não é parte do arquivo %y!</target>
-<source>/sec</source>
-<target>/seg</target>
-
-<source>File does not exist:</source>
-<target>O arquivo não existe:</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>
@@ -303,9 +306,6 @@ A linha de comando é executada cada vez que:
<source>RealtimeSync configuration</source>
<target>Configuração do RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>O arquivo já existe. Deseja substituir?</target>
-
<source>&Restore</source>
<target>&Restaurar</target>
@@ -348,35 +348,38 @@ A linha de comando é executada cada vez que:
<source>FreeFileSync configuration</source>
<target>FreeFileSync configuração</target>
-<source>FreeFileSync Batch Job</source>
-<target>Tarefa em lote do FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>Não foi possível criar arquivo de log!</target>
-
<source>Batch execution</source>
<target>Execução da tarefa em lote</target>
-<source>Stop</source>
-<target>Parar</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>Synchronization aborted!</source>
<target>Sincronização cancelada!</target>
<source>Synchronization completed with errors!</source>
<target>Sincronização finalizada com erros!</target>
+<source>Nothing to synchronize!</source>
+<target>Nada para sincronizar!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sincronização finalizada com sucesso!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Pressione "Alterar" para abrir o modo GUI do FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Pressione "Alterar" para resolver os conflitos na tela principal do FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Alterando para o modo GUI do FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Alterando para a tela principal do FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Não foi possível conectar a sourceforge.net!</target>
@@ -534,9 +537,6 @@ A linha de comando é executada cada vez que:
<source>Items found:</source>
<target>Elementos encontrados:</target>
-<source>Items remaining:</source>
-<target>Elementos restantes:</target>
-
<source>Speed:</source>
<target>Velocidade:</target>
@@ -588,8 +588,8 @@ A linha de comando é executada cada vez que:
<source>&Load</source>
<target>&Carregar</target>
-<source>&Cancel</source>
-<target>&Cancelar</target>
+<source>Cancel</source>
+<target>Cancelar</target>
<source>Select variant:</source>
<target>Selecione um modo:</target>
@@ -628,19 +628,19 @@ A linha de comando é executada cada vez que:
<target>Arquivo/pasta existente somente no lado direito</target>
<source>Left file is newer</source>
-<target>Arquivo à esquerda é mais novo</target>
+<target>O arquivo à esquerda é mais novo</target>
<source>Right file is newer</source>
-<target>Arquivo à direita é mais novo</target>
+<target>O arquivo à direita é mais novo</target>
<source>Files have different content</source>
-<target>Arquivos possuem diferentes conteúdos</target>
+<target>Os arquivos possuem conteúdos diferentes</target>
<source>Conflict/file cannot be categorized</source>
-<target>Conflito/arquivo não pode ser categorizado</target>
+<target>O conflito/arquivo não pode ser categorizado</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Comparar por...</target>
@@ -675,9 +675,6 @@ Os arquivos são considerados iguais se
<source>Synchronizing...</source>
<target>Sincronizando...</target>
-<source>Items processed:</source>
-<target>Elementos processados:</target>
-
<source>&Pause</source>
<target>&Pausar</target>
@@ -1017,9 +1014,6 @@ Excluir: \stuff\temp\*
<source>File list exported!</source>
<target>Lista de arquivos exportada!</target>
-<source>Error writing file:</source>
-<target>Erro ao escrever arquivo:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Excluir: \stuff\temp\*
<source>Paused</source>
<target>Pausado</target>
+<source>Initializing...</source>
+<target>Inicializando...</target>
+
<source>Aborted</source>
<target>Cancelado</target>
<source>Completed</source>
<target>Finalizado</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Cancelar solicitado: Esperando fim da operação...</target>
+<source>Continue</source>
+<target>Continuar</target>
<source>Pause</source>
<target>Pausar</target>
-<source>Continue</source>
-<target>Continuar</target>
-
<source>Cannot find %x</source>
<target>Não foi possível encontrar %x</target>
@@ -1218,65 +1212,65 @@ Excluir: \stuff\temp\*
<pluralform>%x dias</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Não foi possível inicializar o monitoramento de diretórios:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Erro ao monitorar os diretórios.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Não foi possível monitorar o diretório %x.</target>
<source>Conversion error:</source>
<target>Erro de conversão:</target>
-<source>Error deleting file:</source>
-<target>Erro ao apagar arquivo:</target>
+<source>Cannot delete file %x.</source>
+<target>Não foi possível excluir o arquivo %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>O arquivo está bloqueado por outro processo:</target>
-<source>Error moving file:</source>
-<target>Erro ao mover arquivo:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Não foi possível mover o arquivo %x para %y.</target>
-<source>Target file already existing!</source>
-<target>Arquivo de destino já existe!</target>
+<source>Cannot delete directory %x.</source>
+<target>Não foi possível excluir o diretório %x.</target>
-<source>Error moving directory:</source>
-<target>Erro ao mover diretório:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Não foi possível escrever a data de modificação de %x.</target>
-<source>Target directory already existing!</source>
-<target>Diretório de destino já existe!</target>
+<source>Cannot find system function %x.</source>
+<target>Não foi possível encontrar a função de sistema %x.</target>
-<source>Error deleting directory:</source>
-<target>Erro ao apagar diretório:</target>
+<source>Cannot read security context of %x.</source>
+<target>Não foi possível ler o contexto de segurança de %x.</target>
-<source>Error changing modification time:</source>
-<target>Erro ao mudar a hora de modificação:</target>
+<source>Cannot write security context of %x.</source>
+<target>Não foi possível escrever o contexto de segurança de %x.</target>
-<source>Error loading library function:</source>
-<target>Erro ao carregar a biblioteca de funções:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Não foi possível ler as permissões de %x.</target>
-<source>Error reading security context:</source>
-<target>Erro ao ler contexto de segurança:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Não foi possível escrever as permissões de %x.</target>
-<source>Error writing security context:</source>
-<target>Erro ao escrever contexto de segurança:</target>
+<source>Cannot create directory %x.</source>
+<target>Não foi possível criar o diretório %x.</target>
-<source>Error copying file permissions:</source>
-<target>Erro ao copiar permissões do arquivo:</target>
+<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>Error creating directory:</source>
-<target>Erro ao criar diretório:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Não foi possível escrever os atributos de arquivo de %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Erro ao copiar links simbólicos:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Não foi possível copiar o arquivo %x para %y.</target>
-<source>Error copying file:</source>
-<target>Erro ao copiar arquivo:</target>
+<source>Cannot read directory %x.</source>
+<target>Não foi possível ler o diretório %x.</target>
-<source>Error traversing directory:</source>
-<target>Erro ao percorrer diretório:</target>
+<source>Endless loop.</source>
+<target>Loop infinito.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Loop infinito quando percorrendo diretório:</target>
+<source>Cannot set privilege %x.</source>
+<target>Não foi possível estabelecer o privilégio %x.</target>
-<source>Error setting privilege:</source>
-<target>Erro ao definir privilégio:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Não foi possível mover %x para a Lixeira!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Ambos os lados foram alterados desde a última sincronização!</target>
@@ -1302,29 +1296,26 @@ Excluir: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Você pode ignorar esse erro para considerar o diretório como vazio.</target>
-<source>Directory does not exist:</source>
-<target>Diretório não existe:</target>
+<source>Cannot find directory %x.</source>
+<target>Não foi possível encontrar o diretório %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
-<target>Diretórios são dependentes! Cuidado ao definir as regras de sincronização:</target>
+<target>Os diretórios são dependentes! Cuidado ao definir as regras de sincronização:</target>
<source>Preparing synchronization...</source>
<target>Preparando sincronização...</target>
-<source>Out of memory!</source>
-<target>Falta de memória!</target>
-
-<source>File %x has an invalid date!</source>
-<target>Arquivo %x tem uma data inválida!</target>
-
<source>Conflict detected:</source>
<target>Conflito detectado:</target>
+<source>File %x has an invalid date!</source>
+<target>O arquivo %x tem uma data inválida!</target>
+
<source>Files %x have the same date but a different size!</source>
-<target>Arquivos %x têm a mesma data mas tamanhos diferentes!</target>
+<target>Os arquivos %x têm a mesma data mas tamanhos diferentes!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Links Simbólicos %x têm a mesma data mas um destino diferente!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Os links simbólicos %x têm a mesma data mas um destino diferente.</target>
<source>Comparing content of files %x</source>
<target>Comparando conteúdo do arquivo %x</target>
@@ -1339,7 +1330,7 @@ Excluir: \stuff\temp\*
<target>Ambos os lados são iguais</target>
<source>Files/folders differ in attributes only</source>
-<target>Arquivos/pastas se diferenciam apenas nos atributos</target>
+<target>Os arquivos/pastas se diferenciam apenas nos atributos</target>
<source>Copy new file/folder to left</source>
<target>Copiar arquivos/pastas novos para a esquerda</target>
@@ -1407,12 +1398,12 @@ Excluir: \stuff\temp\*
<source>Creating file %x</source>
<target>Criando arquivo %x</target>
-<source>Creating folder %x</source>
-<target>Criando pasta %x</target>
-
<source>Creating symbolic link %x</source>
<target>Criando link simbólico %x</target>
+<source>Creating folder %x</source>
+<target>Criando pasta %x</target>
+
<source>Overwriting file %x</source>
<target>Substituindo arquivo %x</target>
@@ -1429,10 +1420,10 @@ Excluir: \stuff\temp\*
<target>Nome do diretório de destino não pode estar vazio!</target>
<source>Directory for file versioning was not supplied!</source>
-<target>Diretório para controle de versões não foi fornecido!</target>
+<target>O diretório para controle de versões não foi fornecido!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Diretório de origem não existe mais:</target>
+<source>Source directory %x not found.</source>
+<target>O diretório de origem %x não foi encontrado.</target>
<source>Unresolved conflicts existing!</source>
<target>Conflitos não resolvidos existentes!</target>
@@ -1467,12 +1458,6 @@ Excluir: \stuff\temp\*
<source>Generating database...</source>
<target>Gerando banco de dados...</target>
-<source>Nothing to synchronize!</source>
-<target>Nada para sincronizar!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Não foi possível copiar o arquivo bloqueado %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Erro de verificação de dados: Arquivo de origem e destino têm o mesmo conteúdo!</target>
diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng
index e249df6d..c49c9158 100644
--- a/BUILD/Languages/romanian.lng
+++ b/BUILD/Languages/romanian.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Explorează Dosarul</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Abandonare solicitată: Se așteaptă terminarea operației în curs...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Sincronizare Inteligentă</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Codul Erorii Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Eroare la rezolvarea legăturii simbolice:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Nu pot rezolva legătura simbolică %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -137,35 +140,41 @@
<pluralform>%x de Baiți</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Eroare la citirea din baza de date a sincronizării:</target>
+<source>Cannot read file %x.</source>
+<target>Nu pot citi fila %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Eroare la scrierea în baza de date a sincronizării:</target>
+<source>Cannot write file %x.</source>
+<target>Nu pot scrie fila %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Format al bazei de date necompatibil cu versiunea softului:</target>
+<source>Database file %x is incompatible.</source>
+<target>Fila cu baza de date %x este incompatibilă.</target>
<source>Initial synchronization:</source>
<target>Sincronizare inițială:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Una dintre părți nu are o filă de tip bază de date FreeFileSync:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Fila cu baza de date %x nu există încă.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Filele bază de date nu partajează o sesiune comună de sincronizare</target>
+<source>Out of memory!</source>
+<target>Memorie epuizată!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Filele cu baze de date nu partajează o sesiune comună.</target>
<source>An exception occurred!</source>
<target>A apărut o excepție !</target>
-<source>Error reading file attributes:</source>
-<target>Eroare la citirea atributelor filei:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Nu pot citi atributele filei %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Nu pot obține informații despre proces.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Aștept ca dosarul să fie zăvorît (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Eroare la efectuarea zăvorîrii dosarului:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Nu pot seta zăvorîrea dosarului %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x de sec</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Eroare la citirea filei:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Eroare la parsarea filei %x, rîndul %y, coloana %z.</target>
<source>Scanning:</source>
<target>Scanez:</target>
@@ -196,38 +205,32 @@
<pluralform>[%x de Fire]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Filă de configurare FreeFileSync nevalidă!</target>
+<source>/sec</source>
+<target>/sec</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Fila %x nu conține o configurație validă.</target>
-<source>Error parsing configuration file:</source>
-<target>Eroare la parsarea filei de configurare:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Fila de configurație %x a fost deschisă doar parțial.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configuraţie doar parțial deschisă</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Nu pot accesa Serviciul de Conservare a Volumelor [Volume Shadow Copy].</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Nu pot muta %x în Reciclator!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Folosește versiunea pe 64-biți a FreeFileSync pentru a crea conservări (copii de rezervă) pe acest sistem.</target>
<source>Cannot load file %x.</source>
<target>Nu pot deschide fila %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Eroare la accesarea Serviciului de Conservare a Volumelor [Volume Shadow Copy]!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Realizarea de conservări (copii de rezervă) prin sistemul WOW64 nu este suportată. Folosește versiunea pe 64-biți a FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Nu pot determina numele volumului pentru fila:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Calea %x nu conține un nume de volum valid.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Numele volumului %x nu face parte din numele filei %y !</target>
-<source>/sec</source>
-<target>/sec</target>
-
-<source>File does not exist:</source>
-<target>Fila nu există:</target>
+<source>Cannot find file %x.</source>
+<target>Nu pot găsi fila %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Nu pot citi următoarele elemente XML:</target>
@@ -306,9 +309,6 @@ Linia de comandă este executată de fiecare dată cînd:
<source>RealtimeSync configuration</source>
<target>Configurația RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Fila există deja. Vrei s-o suprascrii?</target>
-
<source>&Restore</source>
<target>&Restaurează</target>
@@ -351,35 +351,38 @@ Linia de comandă este executată de fiecare dată cînd:
<source>FreeFileSync configuration</source>
<target>Configurație FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>Sarcină cu set de comenzi FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>Fila jurnal nu poate fi creată!</target>
-
<source>Batch execution</source>
<target>Execută Fila Set</target>
-<source>Stop</source>
-<target>Oprește</target>
+<source>Items processed:</source>
+<target>Elemente Procesate:</target>
+
+<source>Items remaining:</source>
+<target>Elemente Rămase:</target>
<source>Total time:</source>
<target>Timp Total:</target>
+<source>Stop</source>
+<target>Oprește</target>
+
<source>Synchronization aborted!</source>
<target>Sincronizare abandonată!</target>
<source>Synchronization completed with errors!</source>
<target>Sincronizare terminată cu erori!</target>
+<source>Nothing to synchronize!</source>
+<target>Nu e nimic de sincronizat!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sincronizare terminată cu succes!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Apasă "Comută" pentru a deschide modul grafic al FreeFileSync</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Apasă "Comută" pentru a rezolva problemele din dialogul principal FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Comut la modul grafic al FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Comut la dialogul principal FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Conectarea la situl sourceforge.net nu poate fi realizată!</target>
@@ -537,9 +540,6 @@ Linia de comandă este executată de fiecare dată cînd:
<source>Items found:</source>
<target>Elemente Găsite:</target>
-<source>Items remaining:</source>
-<target>Elemente Rămase:</target>
-
<source>Speed:</source>
<target>Viteză:</target>
@@ -591,8 +591,8 @@ Linia de comandă este executată de fiecare dată cînd:
<source>&Load</source>
<target>&Deschide</target>
-<source>&Cancel</source>
-<target>&Anulează</target>
+<source>Cancel</source>
+<target>Anulează</target>
<source>Select variant:</source>
<target>Selectează Varianta de Sincronizare:</target>
@@ -642,8 +642,8 @@ Linia de comandă este executată de fiecare dată cînd:
<source>Conflict/file cannot be categorized</source>
<target>Conflictul de file nu poate fi inclus într-o anumită categorie</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Compară după:</target>
@@ -678,9 +678,6 @@ este același
<source>Synchronizing...</source>
<target>Sincronizare Aflată în Curs...</target>
-<source>Items processed:</source>
-<target>Elemente Procesate:</target>
-
<source>&Pause</source>
<target>&Pauzează</target>
@@ -717,9 +714,6 @@ este același
<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>&OK</target>
-
<source>&Retry</source>
<target>&Reîncearcă</target>
@@ -1020,9 +1014,6 @@ Excluse: \stuff\temp\*
<source>File list exported!</source>
<target>Lista de file a fost exportată!</target>
-<source>Error writing file:</source>
-<target>Eroare la scrierea filei:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1072,21 +1063,21 @@ Excluse: \stuff\temp\*
<source>Paused</source>
<target>Sincronizare Pauzată</target>
+<source>Initializing...</source>
+<target>Inițializez...</target>
+
<source>Aborted</source>
<target>Sincronizare Abandonată</target>
<source>Completed</source>
<target>Sincronizare Terminată</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abandonare solicitată: Se așteaptă terminarea operației în curs...</target>
+<source>Continue</source>
+<target>Continuă</target>
<source>Pause</source>
<target>Pauzează</target>
-<source>Continue</source>
-<target>Continuă</target>
-
<source>Cannot find %x</source>
<target>Nu pot găsi %x</target>
@@ -1230,65 +1221,65 @@ Excluse: \stuff\temp\*
<pluralform>%x de zile</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Nu pot inițializa monitorizarea dosarelor:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Eroare la monitorizarea dosarelor.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Nu pot monitoriza dosarul %x.</target>
<source>Conversion error:</source>
<target>Eroare de convertire:</target>
-<source>Error deleting file:</source>
-<target>Eroare la ștergerea filei:</target>
+<source>Cannot delete file %x.</source>
+<target>Nu pot șterge fila %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Fila este zăvorîtă [locked] de alt proces:</target>
-<source>Error moving file:</source>
-<target>Eroare la mutarea filei:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Nu pot muta fila %x în %y.</target>
-<source>Target file already existing!</source>
-<target>Fila țintă există deja!</target>
+<source>Cannot delete directory %x.</source>
+<target>Nu pot șterge dosarul %x.</target>
-<source>Error moving directory:</source>
-<target>Eroare la mutarea dosarului:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Nu pot scrie modificarea timpului pentru %x.</target>
-<source>Target directory already existing!</source>
-<target>Dosarul țintă există deja!</target>
+<source>Cannot find system function %x.</source>
+<target>Nu pot găsi funcția de sistem %x.</target>
-<source>Error deleting directory:</source>
-<target>Eroare la ștergerea dosarului:</target>
+<source>Cannot read security context of %x.</source>
+<target>Nu pot citi contextul de securitate pentru %x.</target>
-<source>Error changing modification time:</source>
-<target>Eroare la schimbarea datei de modificare:</target>
+<source>Cannot write security context of %x.</source>
+<target>Nu pot scrie contextul de securitate pentru %x.</target>
-<source>Error loading library function:</source>
-<target>Eroare la deschiderea bibliotecii de funcții:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Nu pot citi permisiunile lui %x.</target>
-<source>Error reading security context:</source>
-<target>Eroare la citirea contextului de securitate:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Nu pot scrie permisiunile lui %x.</target>
-<source>Error writing security context:</source>
-<target>Eroare la scrierea contextului de securitate:</target>
+<source>Cannot create directory %x.</source>
+<target>Nu pot crea dosarul %x.</target>
-<source>Error copying file permissions:</source>
-<target>Eroare la copierea permisiunilor filei:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Nu pot copia legătura simbolică %x în %y.</target>
-<source>Error creating directory:</source>
-<target>Eroare la crearea dosarului:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nu pot scrie atributele de filă ale lui %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Eroare la copierea legăturii simbolice:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Nu pot copia fila %x în %y.</target>
-<source>Error copying file:</source>
-<target>Eroare la copierea filei:</target>
+<source>Cannot read directory %x.</source>
+<target>Nu pot citi dosarul %x.</target>
-<source>Error traversing directory:</source>
-<target>Eroare la parcurgerea dosarului:</target>
+<source>Endless loop.</source>
+<target>Buclă infinită.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Buclă infinită la parcurgerea dosarului:</target>
+<source>Cannot set privilege %x.</source>
+<target>Nu pot seta privilegiul %x.</target>
-<source>Error setting privilege:</source>
-<target>Eroare la setarea privilegiului:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Nu pot muta %x în Reciclator!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Ambele părți s-au modificat de la ultima sincronizare!</target>
@@ -1314,8 +1305,8 @@ Excluse: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Poți ignora această eroare dacă vrei ca dosarul să fie considerat gol.</target>
-<source>Directory does not exist:</source>
-<target>Dosarul nu există:</target>
+<source>Cannot find directory %x.</source>
+<target>Nu pot găsi dosarul %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Dosarele sînt interdependente! Atenție la setarea regulilor de sincronizare:</target>
@@ -1323,20 +1314,17 @@ Excluse: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Pregătesc sincronizarea...</target>
-<source>Out of memory!</source>
-<target>Memorie epuizată!</target>
+<source>Conflict detected:</source>
+<target>Conflict detectat:</target>
<source>File %x has an invalid date!</source>
<target>Fila %x are o dată nevalidă !</target>
-<source>Conflict detected:</source>
-<target>Conflict detectat:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Filele %x au dată identică, dar mărime diferită!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Simlegăturile %x au dată identică, dar ținte diferite!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Legăturile simbolice %x au aceeași dată, dar ținte diferite.</target>
<source>Comparing content of files %x</source>
<target>Compar conținutul filelor %x</target>
@@ -1419,12 +1407,12 @@ Excluse: \stuff\temp\*
<source>Creating file %x</source>
<target>Creez fila %x</target>
-<source>Creating folder %x</source>
-<target>Creez dosarul %x</target>
-
<source>Creating symbolic link %x</source>
<target>Creez legătura simbolică %x</target>
+<source>Creating folder %x</source>
+<target>Creez dosarul %x</target>
+
<source>Overwriting file %x</source>
<target>Suprascriu fila %x</target>
@@ -1443,8 +1431,8 @@ Excluse: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Dosarul pentru versionarea filelor n-a fost specificat!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Dosarul sursă nu mai există:</target>
+<source>Source directory %x not found.</source>
+<target>Dosarul sursă %x nu a fost găsit.</target>
<source>Unresolved conflicts existing!</source>
<target>Există conflicte nerezolvate!</target>
@@ -1479,12 +1467,6 @@ Excluse: \stuff\temp\*
<source>Generating database...</source>
<target>Generez baza de date...</target>
-<source>Nothing to synchronize!</source>
-<target>Nu e nimic de sincronizat!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Nu pot copia fila zăvorîtă %x</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Eroare la verificarea datelor: Filele sursă și țintă au conținut diferit!</target>
diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng
index 01f4eded..a5008215 100644
--- a/BUILD/Languages/russian.lng
+++ b/BUILD/Languages/russian.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Обзор папок</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹: Ожидайте, пока Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚ÑÑ...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - ÐвтоматичеÑÐºÐ°Ñ ÑинхронизациÑ</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Код ошибки Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Ошибка при решении ÑимволичеÑкой ÑÑылки:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Ðе удаетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÑŒ ÑимволичеÑкую ÑÑылку %x.</target>
<source>%x MB</source>
<target>%x МБ</target>
@@ -137,35 +140,41 @@
<pluralform>%x Байт</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Ошибка при чтении из базы данных Ñинхронизации:</target>
+<source>Cannot read file %x.</source>
+<target>Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ файл %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Ошибка при запиÑи в базу данных Ñинхронизации:</target>
+<source>Cannot write file %x.</source>
+<target>Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать файл %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>ÐеÑовмеÑтимый формат базы данных Ñинхронизации:</target>
+<source>Database file %x is incompatible.</source>
+<target>Файл базы данных %x неÑовмеÑтим.</target>
<source>Initial synchronization:</source>
<target>ÐŸÐµÑ€Ð²Ð¾Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ ÑинхронизациÑ:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Одного из файлов баз данных FreeFileSync еще не ÑущеÑтвует:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Файл базы данных %x еще не ÑущеÑтвует.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Файлы баз данных не имеют общей ÑеÑÑии Ñинхронизации:</target>
+<source>Out of memory!</source>
+<target>ÐедоÑтаточно памÑти!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Файлы баз данных не имеют общей ÑеÑÑии.</target>
<source>An exception occurred!</source>
<target>ИÑключение произошло!</target>
-<source>Error reading file attributes:</source>
-<target>Ошибка при чтении параметров файла:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ атрибуты файла %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ информацию о процеÑÑе.</target>
<source>Waiting while directory is locked (%x)...</source>
-<target>Ожидание ÑнÑÑ‚Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ Ñ Ð¿Ð°Ð¿ÐºÐ¸ (%x)...</target>
+<target>Ожидание ÑнÑÑ‚Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ Ñ Ð¿Ð°Ð¿ÐºÐ¸ %x...</target>
-<source>Error setting directory lock:</source>
-<target>Ошибка блокировки папки:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Ðе удаетÑÑ ÑƒÑтановить блокировку папка %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x Ñекунд</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Ошибка при чтении файла:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Ошибка при разборе файла %x, Ñтрока %y, колонка %z.</target>
<source>Scanning:</source>
<target>Сканирую:</target>
@@ -196,38 +205,32 @@
<pluralform>[%x потоков]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Ðеверный файл конфигурации FreeFileSync!</target>
+<source>/sec</source>
+<target>/Ñ</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Файл %x не Ñодержит дейÑтвительной конфигурации.</target>
-<source>Error parsing configuration file:</source>
-<target>Ошибка при анализе файла наÑтроек Ñинхронизации:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Файл конфигурации %x загрузилÑÑ Ñ‡Ð°Ñтично.</target>
-<source>Configuration loaded partially only:</source>
-<target>ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ð»Ð°ÑÑŒ чаÑтично:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к Ñлужбе Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ðевозможно перемеÑтить %x в "Корзину"!</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>ПожалуйÑта, иÑпользуйте 64-разрÑдную верÑию FreeFileSync Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚ÐµÐ½ÐµÐ²Ñ‹Ñ… копий на Ñтой ÑиÑтеме.</target>
<source>Cannot load file %x.</source>
<target>Ðе удаетÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ файл %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Ошибка доÑтупа к Ñлужбе Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Создание теневых копий на WOW64 не поддерживаетÑÑ. ПожалуйÑта, иÑпользуйте FreeFileSync 64-разрÑдной верÑии.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Ðевозможно определить Ð¸Ð¼Ñ Ñ‚Ð¾Ð¼Ð° Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð°:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Путь %x не Ñодержит Ð¸Ð¼Ñ Ñ‚Ð¾Ð¼Ð°.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Ð˜Ð¼Ñ Ñ‚Ð¾Ð¼Ð° %x не ÑвлÑетÑÑ Ñ‡Ð°Ñтью имени файла %y!</target>
-<source>/sec</source>
-<target>/Ñ</target>
-
-<source>File does not exist:</source>
-<target>Файл не ÑущеÑтвует:</target>
+<source>Cannot find file %x.</source>
+<target>Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ файл %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Ðевозможно прочитать Ñледующие XML Ñлементы:</target>
@@ -257,7 +260,7 @@
<target>ИнÑтрукциÑ:</target>
<source>1. Select directories to monitor.</source>
-<target>1. Выберите папки Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð°;</target>
+<target>1. Выберите папки Ð´Ð»Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ;</target>
<source>2. Enter a command line.</source>
<target>2. Введите командную Ñтроку;</target>
@@ -306,9 +309,6 @@ The command line is executed each time:
<source>RealtimeSync configuration</source>
<target>ÐаÑтройка RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Файл уже ÑущеÑтвует. ПерезапиÑать?</target>
-
<source>&Restore</source>
<target>&ВоÑÑтановить</target>
@@ -316,7 +316,7 @@ The command line is executed each time:
<target>&Выход</target>
<source>Monitoring active...</source>
-<target>Мониторинг включен...</target>
+<target>Ðаблюдение включено...</target>
<source>Waiting for missing directories...</source>
<target>Ожидание пропущенных папок...</target>
@@ -351,35 +351,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>ÐаÑтройка FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>Пакетное задание FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>Ðевозможно Ñоздать лог-файл!</target>
-
<source>Batch execution</source>
<target>Выполнение пакетного заданиÑ</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ð¼ÐµÐ½ÐµÐ½Ð°!</target>
<source>Synchronization completed with errors!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°ÐºÐ¾Ð½Ñ‡ÐµÐ½Ð° Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸!</target>
+<source>Nothing to synchronize!</source>
+<target>Ðичего нет Ð´Ð»Ñ Ñинхронизации!</target>
+
<source>Synchronization completed successfully!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾ÑˆÐ»Ð° уÑпешно!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Ðажмите "Переключить" Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÑŒÑкого графичеÑкого интерфейÑа FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Ðажмите "Переключить" Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ в главном окне FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Переключение на пользовательÑкий графичеÑкий Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Переключение на главное окно FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Ðевозможно ÑоединитьÑÑ Ñ sourceforge.net!</target>
@@ -540,9 +543,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>Элементов найдено:</target>
-<source>Items remaining:</source>
-<target>Элементов оÑталоÑÑŒ:</target>
-
<source>Speed:</source>
<target>СкороÑÑ‚ÑŒ:</target>
@@ -594,8 +594,8 @@ The command line is executed each time:
<source>&Load</source>
<target>&Загрузить</target>
-<source>&Cancel</source>
-<target>&Отмена</target>
+<source>Cancel</source>
+<target>Отмена</target>
<source>Select variant:</source>
<target>Варианты Ñинхронизации</target>
@@ -645,8 +645,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>Конфликт/файл не может быть отнеÑен к какой-либо категории</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Критерии ÑравнениÑ</target>
@@ -676,9 +676,6 @@ is the same
<source>Synchronizing...</source>
<target>СинхронизациÑ...</target>
-<source>Items processed:</source>
-<target>Элементов обработано:</target>
-
<source>&Pause</source>
<target>&Пауза</target>
@@ -1018,9 +1015,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>СпиÑок файлов ÑкÑпортирован!</target>
-<source>Error writing file:</source>
-<target>Ошибка при запиÑи файла:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1070,21 +1064,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>Пауза</target>
+<source>Initializing...</source>
+<target>ИнициализациÑ...</target>
+
<source>Aborted</source>
<target>Отменено</target>
<source>Completed</source>
<target>Завершено</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ñ‹: Ожидайте, пока Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚ÑÑ...</target>
+<source>Continue</source>
+<target>Продолжить</target>
<source>Pause</source>
<target>Пауза</target>
-<source>Continue</source>
-<target>Продолжить</target>
-
<source>Cannot find %x</source>
<target>Ðевозможно найти %x</target>
@@ -1231,65 +1225,65 @@ Exclude: \stuff\temp\*
<pluralform>%x дней</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Ðе удалоÑÑŒ инициализировать папку Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð°:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Ошибка при мониторинге папок.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Ðе удаетÑÑ Ð½Ð°Ð±Ð»ÑŽÐ´Ð°Ñ‚ÑŒ папку %x.</target>
<source>Conversion error:</source>
<target>Ошибка преобразованиÑ:</target>
-<source>Error deleting file:</source>
-<target>Ошибка при удалении файла:</target>
+<source>Cannot delete file %x.</source>
+<target>Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ файл %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Файл заблокирован другим процеÑÑом:</target>
-<source>Error moving file:</source>
-<target>Ошибка Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Ðе удаетÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти файл %x в %y.</target>
-<source>Target file already existing!</source>
-<target>Конечный файл уже ÑущеÑтвует!</target>
+<source>Cannot delete directory %x.</source>
+<target>Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ папку %x.</target>
-<source>Error moving directory:</source>
-<target>Ошибка Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð¿Ð°Ð¿ÐºÐ¸:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать Ð²Ñ€ÐµÐ¼Ñ Ð¼Ð¾Ð´Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ файла %x.</target>
-<source>Target directory already existing!</source>
-<target>ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° уже ÑущеÑтвует!</target>
+<source>Cannot find system function %x.</source>
+<target>Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ ÑиÑтемную функцию %x.</target>
-<source>Error deleting directory:</source>
-<target>Ошибка при удалении папки:</target>
+<source>Cannot read security context of %x.</source>
+<target>Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ контекÑÑ‚ безобаÑноÑти %x.</target>
-<source>Error changing modification time:</source>
-<target>Ошибка при изменении времени модификации файла:</target>
+<source>Cannot write security context of %x.</source>
+<target>Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать контекÑÑ‚ безобаÑноÑти %x.</target>
-<source>Error loading library function:</source>
-<target>Ошибка при загрузке функции библиотеки:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚ÑŒ права доÑтупа %x.</target>
-<source>Error reading security context:</source>
-<target>Ошибка при чтении контекÑта безобаÑноÑти:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать права доÑтупа %x.</target>
-<source>Error writing security context:</source>
-<target>Ошибка при запиÑи контекÑта безобаÑноÑти:</target>
+<source>Cannot create directory %x.</source>
+<target>Ðе удаетÑÑ Ñоздать папку %x.</target>
-<source>Error copying file permissions:</source>
-<target>Ошибка при копировании прав доÑтупа:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Ðе удаетÑÑ Ñкопировать Ñимвольную ÑÑылку %x в %y.</target>
-<source>Error creating directory:</source>
-<target>Ошибка при Ñоздании папки:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ðе удаетÑÑ Ð·Ð°Ð¿Ð¸Ñать атрибуты файла %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Ошибка при копировании Ñимвольной ÑÑылки:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Ðе удаетÑÑ Ñкопировать файл %x в %y.</target>
-<source>Error copying file:</source>
-<target>Ошибка при копировании файла:</target>
+<source>Cannot read directory %x.</source>
+<target>Ðе удаетÑÑ Ð¿Ñ€Ð¾Ñ‡ÐµÑÑ‚ÑŒ папку %x.</target>
-<source>Error traversing directory:</source>
-<target>Ошибка при переÑечении папок:</target>
+<source>Endless loop.</source>
+<target>БеÑконечный цикл.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Зацикливание при вÑтрече переÑекающихÑÑ Ð¿ÑƒÑ‚ÐµÐ¹:</target>
+<source>Cannot set privilege %x.</source>
+<target>Ðе удаетÑÑ ÑƒÑтановить привелегии %x.</target>
-<source>Error setting privilege:</source>
-<target>Ошибка уÑтановки привилегий:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ðевозможно перемеÑтить %x в "Корзину"!</target>
<source>Both sides have changed since last synchronization!</source>
<target>Со времени поÑледней Ñинхронизации Ñ Ð¾Ð±ÐµÐ¸Ñ… Ñторон произошли изменениÑ!</target>
@@ -1318,8 +1312,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Ð’Ñ‹ можете проигнорировать ошибку, принÑв папку за пуÑтую.</target>
-<source>Directory does not exist:</source>
-<target>Папка не ÑущеÑтвует:</target>
+<source>Cannot find directory %x.</source>
+<target>Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ папку %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>ЗавиÑимые папки! Будьте внимательны при наÑтройке правил Ñинхронизации:</target>
@@ -1327,20 +1321,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Подготовка к Ñинхронизации...</target>
-<source>Out of memory!</source>
-<target>ÐедоÑтаточно памÑти!</target>
+<source>Conflict detected:</source>
+<target>Обнаружен конфликт:</target>
<source>File %x has an invalid date!</source>
<target>Файл %x имеет недейÑтвительную дату!</target>
-<source>Conflict detected:</source>
-<target>Обнаружен конфликт:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Файлы %x имеют одинаковую дату, но различаютÑÑ Ð¿Ð¾ размеру!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Ð¡Ð¸Ð¼Ð²Ð¾Ð»ÑŒÐ½Ð°Ñ ÑÑылка %x имеет ту же дату, но различное Ñодержание!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Ð¡Ð¸Ð¼Ð²Ð¾Ð»ÑŒÐ½Ð°Ñ ÑÑылка %x имеет ту же дату, но отличающуюÑÑ Ñ†ÐµÐ»ÑŒ.</target>
<source>Comparing content of files %x</source>
<target>Сравнение ÑÐ¾Ð´ÐµÑ€Ð¶Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² %x</target>
@@ -1423,12 +1414,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>Создание файла %x</target>
-<source>Creating folder %x</source>
-<target>Создание папки %x</target>
-
<source>Creating symbolic link %x</source>
<target>Создание Ñимвольной ÑÑылки %x</target>
+<source>Creating folder %x</source>
+<target>Создание папки %x</target>
+
<source>Overwriting file %x</source>
<target>ПерезапиÑÑŒ файла %x</target>
@@ -1447,8 +1438,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Папка Ð´Ð»Ñ Ñтарых верÑий файлов не была указана!</target>
-<source>Source directory does not exist anymore:</source>
-<target>ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° больше не ÑущеÑтвует:</target>
+<source>Source directory %x not found.</source>
+<target>ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° %x не найдена.</target>
<source>Unresolved conflicts existing!</source>
<target>СущеÑтвуют нерешенные конфликты</target>
@@ -1483,12 +1474,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>Создание базы данных...</target>
-<source>Nothing to synchronize!</source>
-<target>Ðичего нет Ð´Ð»Ñ Ñинхронизации!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Ðевозможно Ñкопировать заблокированный файл %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Ошибка проверки данных: иÑходный и конечный файлы имеют разное Ñодержание!</target>
diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng
index 3a7cf10b..975074be 100644
--- a/BUILD/Languages/slovenian.lng
+++ b/BUILD/Languages/slovenian.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Brskaj po imeniku</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Zahtevana je bila prekinitev: Äakam, da se zakljuÄi trenutna operacija...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Avtomatizirana sinhronizacija</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux koda napake %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Napaka pri razreÅ¡evanju simboliÄne povezave:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Ne morem razreÅ¡iti simboliÄne povezave %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -138,35 +141,41 @@
<pluralform>%x Bajtov</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Napaka pri branju iz sinhronizacijske podatkovne baze:</target>
+<source>Cannot read file %x.</source>
+<target>Ne morem prebrati datoteke %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Napaka pri pisanju v sinhronizacijsko podatkovno bazo:</target>
+<source>Cannot write file %x.</source>
+<target>Ne morem zapisati datoteke %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Nekompatibilen format sinhronizacijske podatkovne baze:</target>
+<source>Database file %x is incompatible.</source>
+<target>Datoteka podatkovne baze %x je nekopatibilna.</target>
<source>Initial synchronization:</source>
<target>ZaÄetna sinhronizacija:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Ena od FreeFileSync datotek podatkovne baze Å¡e en obstaja:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Datoteka podatkovne baze %x Å¡e ne obstaja.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Datoteke podatkovne baze si ne delijo skupne sinhronizacijske seje:</target>
+<source>Out of memory!</source>
+<target>Zmanjkalo pomnilnika!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Datoteke podatkovne baze si ne delijo skupne seje.</target>
<source>An exception occurred!</source>
<target>Zgodila se je napaka!</target>
-<source>Error reading file attributes:</source>
-<target>Napaka pri branju atributov datoteke:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Ne morem brati datoteÄnih atributov od %x.</target>
+
+<source>Cannot get process information.</source>
+<target>Ne morem pridobiti informacij o procesu.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>ÄŒakam, medtem ko se zaklepa imenik (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Napaka pri nastavljanju zaklepanja imenika:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Ne morem nastaviti zaklepanja imenika %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -179,8 +188,8 @@
<pluralform>%x sek</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Napaka pri branju datoteke:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Napaka pri razÄlenjevanju datoteke %x, vrstica %y, stolpec %z.</target>
<source>Scanning:</source>
<target>Pregledujem:</target>
@@ -199,38 +208,32 @@
<pluralform>[%x niti]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Neveljavna FreeFileSync nastavitvena datoteka!</target>
+<source>/sec</source>
+<target>/sek</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Datoteka %x ne vsebuje veljavnih nastavitev</target>
-<source>Error parsing configuration file:</source>
-<target>Napaka pri preverjanju konfiguracijske datoteke:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Nastavitvena datoteka %x naložena samo delno.</target>
-<source>Configuration loaded partially only:</source>
-<target>Nastavitev naložena samo delno:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Ne morem dostopati do servisa Volume Shadow Copy</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ne morem premakniti %x v Koš</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Prosimo uporabite 64-bitno razliÄico FreeFileSync za ustvarjanje senÄnih kopij na tem sistemu.</target>
<source>Cannot load file %x.</source>
<target>Ne morem naložiti datoteko %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Napaka pri dostopu do servisa senÄnih kopij!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Ustvarjanje senÄnih kopij na WOW63 ni podprto. Prosimo uporabite 64-bitno FreeFileSync razliÄico.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Ne morem doloÄiti imena volumna za datoteko:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Pot %x ne vsebuje ime volumna.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Ime volumna %x ni del imena datoteke %y!</target>
-<source>/sec</source>
-<target>/sek</target>
-
-<source>File does not exist:</source>
-<target>Datoteka ne obstaja:</target>
+<source>Cannot find file %x.</source>
+<target>Ne morem najti datoteke %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Ne morem brati naslednje XML elemente:</target>
@@ -309,9 +312,6 @@ Ukazna vrstica se izvrÅ¡i vsakiÄ ko:
<source>RealtimeSync configuration</source>
<target>RealtimeSync nastavitve</target>
-<source>File already exists. Overwrite?</source>
-<target>Datoteka že obstaja. Prepišem?</target>
-
<source>&Restore</source>
<target>&Obnovi</target>
@@ -354,35 +354,38 @@ Ukazna vrstica se izvrÅ¡i vsakiÄ ko:
<source>FreeFileSync configuration</source>
<target>FreeFileSync konfiguracija</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Paketno opravilo</target>
-
-<source>Unable to create log file!</source>
-<target>Ne morem ustvariti datoteko za beleženje!</target>
-
<source>Batch execution</source>
<target>Paketno izvajanje</target>
-<source>Stop</source>
-<target>Ustavi</target>
+<source>Items processed:</source>
+<target>Obdelanih elementov:</target>
+
+<source>Items remaining:</source>
+<target>Preostalih elementov:</target>
<source>Total time:</source>
<target>Celoten Äas:</target>
+<source>Stop</source>
+<target>Ustavi</target>
+
<source>Synchronization aborted!</source>
<target>Sinhronizacija prekinjena!</target>
<source>Synchronization completed with errors!</source>
<target>Sinhronizacija se je konÄala z napakami!</target>
+<source>Nothing to synchronize!</source>
+<target>NiÄ za sinhronizirati!</target>
+
<source>Synchronization completed successfully!</source>
<target>Sinhronizacija uspeÅ¡no zakljuÄena!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Pritisnite "Zamenjaj", da odprete FreeFileSync GUI naÄin.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Pritisnite "Preklopi", da razrešite vprašanja v glavnem pogovornem oknu FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Preklapljam v FreeFileSync GUI naÄin...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Preklapljam na FreeFileSync glavno pogovorno okno...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Ne morem se povezati na sourceforge.net!</target>
@@ -540,9 +543,6 @@ Ukazna vrstica se izvrÅ¡i vsakiÄ ko:
<source>Items found:</source>
<target>Najdenih elementov:</target>
-<source>Items remaining:</source>
-<target>Preostalih elementov:</target>
-
<source>Speed:</source>
<target>Hitrost:</target>
@@ -594,8 +594,8 @@ Ukazna vrstica se izvrÅ¡i vsakiÄ ko:
<source>&Load</source>
<target>&Naloži</target>
-<source>&Cancel</source>
-<target>&PrekliÄi</target>
+<source>Cancel</source>
+<target>PrekliÄi</target>
<source>Select variant:</source>
<target>Izberite varianto:</target>
@@ -645,8 +645,8 @@ Ukazna vrstica se izvrÅ¡i vsakiÄ ko:
<source>Conflict/file cannot be categorized</source>
<target>Spor/datoteka ne more biti kategorizirana</target>
-<source>&OK</source>
-<target>&V redu</target>
+<source>OK</source>
+<target>V redu</target>
<source>Compare by...</source>
<target>Primerjaj po...</target>
@@ -681,9 +681,6 @@ enaka
<source>Synchronizing...</source>
<target>Sinhroniziram...</target>
-<source>Items processed:</source>
-<target>Obdelanih elementov:</target>
-
<source>&Pause</source>
<target>&Premor</target>
@@ -730,7 +727,7 @@ enaka
<target>Ne prikaži veÄ tega pogovornega okna</target>
<source>&Switch</source>
-<target>&Zamenjaj</target>
+<target>&Preklopi</target>
<source>&Yes</source>
<target>&Da</target>
@@ -1023,9 +1020,6 @@ IzkljuÄi: \stuff\temp\*
<source>File list exported!</source>
<target>Seznam datotek je bil izvožen!</target>
-<source>Error writing file:</source>
-<target>Napaka pri pisanju datoteke:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1079,21 +1073,21 @@ IzkljuÄi: \stuff\temp\*
<source>Paused</source>
<target>Na premoru</target>
+<source>Initializing...</source>
+<target>Inicializiram...</target>
+
<source>Aborted</source>
<target>Prekinitev uspela</target>
<source>Completed</source>
<target>ZakljuÄeno</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Zahtevana je bila prekinitev: Äakam, da se zakljuÄi trenutna operacija...</target>
+<source>Continue</source>
+<target>Nadaljuj</target>
<source>Pause</source>
<target>Premor</target>
-<source>Continue</source>
-<target>Nadaljuj</target>
-
<source>Cannot find %x</source>
<target>Ne najdem %x</target>
@@ -1242,65 +1236,65 @@ IzkljuÄi: \stuff\temp\*
<pluralform>%x dni</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Ne morem zaÄeti nadzorovanja imenikov:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Napaka pri nadzorovanju imenikov.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Ne morem nadzorovati imenika %x.</target>
<source>Conversion error:</source>
<target>Napaka pri pretvorbi:</target>
-<source>Error deleting file:</source>
-<target>Napaka pri brisanju datoteke:</target>
+<source>Cannot delete file %x.</source>
+<target>Ne morem izbrisati datoteke %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>Datoteka je zaklenjena s strani drugega procesa:</target>
-<source>Error moving file:</source>
-<target>Napaka pri premikanju datoteke:</target>
+<source>Cannot move file %x to %y.</source>
+<target>Ne morem premakniti datoteko %x v %y.</target>
-<source>Target file already existing!</source>
-<target>Ciljna datoteka že obstaja!</target>
+<source>Cannot delete directory %x.</source>
+<target>Ne morem izbrisati imenika %x.</target>
-<source>Error moving directory:</source>
-<target>Napaka pri premikanju imenika:</target>
+<source>Cannot write modification time of %x.</source>
+<target>Ne morem zapisati Äasa spremembe od %x.</target>
-<source>Target directory already existing!</source>
-<target>Ciljni imenik že obstaja!</target>
+<source>Cannot find system function %x.</source>
+<target>Ne morem najti sistemske funkcije %x.</target>
-<source>Error deleting directory:</source>
-<target>Napaka pri brisanju imenika:</target>
+<source>Cannot read security context of %x.</source>
+<target>Ne morem prebrati varnostnega konteksta od %x.</target>
-<source>Error changing modification time:</source>
-<target>Napaka pri spreminjanju Äasa modifikacije:</target>
+<source>Cannot write security context of %x.</source>
+<target>Ne morem zapisati varnostni kontekst od %x</target>
-<source>Error loading library function:</source>
-<target>Napaka pri nalaganju funkcije iz knjižnice:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Ne morem prebrati dovoljenja od %x.</target>
-<source>Error reading security context:</source>
-<target>Napaka pri branju varnostne skladnosti:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Ne morem zapisati dovoljenj od %x.</target>
-<source>Error writing security context:</source>
-<target>Napaka pri pisanju varnostne skladnosti:</target>
+<source>Cannot create directory %x.</source>
+<target>Ne morem ustvariti imenika %x.</target>
-<source>Error copying file permissions:</source>
-<target>Napaka pri kopiranju datoteÄnih dovoljenj:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Ne morem kopirati simboliÄnih povezav %x v %y.</target>
-<source>Error creating directory:</source>
-<target>Napaka pri ustvarjanju imenika:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ne morem zapisati datoteÄnih atributov od %x.</target>
-<source>Error copying symbolic link:</source>
-<target>Napaka pri kopiranju simboliÄnih povezav:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Ne morem kopirati datoteke %x v %y.</target>
-<source>Error copying file:</source>
-<target>Napaka pri kopiranju datoteke:</target>
+<source>Cannot read directory %x.</source>
+<target>Ne morem prebrati imenika %x.</target>
-<source>Error traversing directory:</source>
-<target>Napaka pri prehajanju imenika:</target>
+<source>Endless loop.</source>
+<target>NeskonÄno zazankano</target>
-<source>Endless loop when traversing directory:</source>
-<target>NeskonÄna zanka pri prehodu imenika:</target>
+<source>Cannot set privilege %x.</source>
+<target>Ne morem nastaviti privilegija %x.</target>
-<source>Error setting privilege:</source>
-<target>Napaka pri nastavljanju privilegija:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ne morem premakniti %x v Koš</target>
<source>Both sides have changed since last synchronization!</source>
<target>Obe strani sta se spremenili od zadnje sinhronizacije!</target>
@@ -1326,8 +1320,8 @@ IzkljuÄi: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>To napako z obravnavanjem imenika kot praznega lahko ignorirate.</target>
-<source>Directory does not exist:</source>
-<target>Imenik ne obstaja:</target>
+<source>Cannot find directory %x.</source>
+<target>Ne morem najti imenika %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Imeniki so v odvisnosti! Bodite pozorni, ko nastavljate sinhronizacijska pravila:</target>
@@ -1335,20 +1329,17 @@ IzkljuÄi: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Pripravljam sinhronizacijo...</target>
-<source>Out of memory!</source>
-<target>Zmanjkalo pomnilnika!</target>
+<source>Conflict detected:</source>
+<target>Zaznan spor:</target>
<source>File %x has an invalid date!</source>
<target>Datoteka %x ima neveljaven datum!</target>
-<source>Conflict detected:</source>
-<target>Zaznan spor:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Datoteki %x imata enak datum ampak razliÄno velikost!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>SimboliÄne povezave %x imajo isti datum, vendar razliÄni cilj!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>SimboliÄne povezave %x imajo isti datum, vendar razliÄno tarÄo.</target>
<source>Comparing content of files %x</source>
<target>Primerjam vsebino datotek %x</target>
@@ -1431,12 +1422,12 @@ IzkljuÄi: \stuff\temp\*
<source>Creating file %x</source>
<target>Ustvarjam datoteko %x</target>
-<source>Creating folder %x</source>
-<target>Ustvarjam mapo %x</target>
-
<source>Creating symbolic link %x</source>
<target>Ustvarjam simboliÄno povezavo %x</target>
+<source>Creating folder %x</source>
+<target>Ustvarjam mapo %x</target>
+
<source>Overwriting file %x</source>
<target>Prepisujem datoteko %x</target>
@@ -1455,8 +1446,8 @@ IzkljuÄi: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Imenik za upravljanje z datoteÄnimi raliÄicami ni bil podan!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Izvorni imenik ne obstaja veÄ:</target>
+<source>Source directory %x not found.</source>
+<target>Izvorni imenik %x ni bil najden.</target>
<source>Unresolved conflicts existing!</source>
<target>Obstajajo nerešeni spori!</target>
@@ -1465,7 +1456,7 @@ IzkljuÄi: \stuff\temp\*
<target>Lahko ignorirate spore in nadaljujete s sinhronizacijo.</target>
<source>Significant difference detected:</source>
-<target>Zaznana je važna razlika:</target>
+<target>Zaznana je pomembna razlika:</target>
<source>More than 50% of the total number of files will be copied or deleted!</source>
<target>VeÄ kot 50% od celotnega Å¡tevila datotek bo kopiranih ali izbrisanih!</target>
@@ -1491,12 +1482,6 @@ IzkljuÄi: \stuff\temp\*
<source>Generating database...</source>
<target>Ustvarjam podatkovno bazo...</target>
-<source>Nothing to synchronize!</source>
-<target>NiÄ za sinhronizirati!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Ne morem kopirati zaklenjeno datoteko %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Napaka pri preverjanju podatkov: izvorna in ciljna datoteka imata razliÄno vsebino!</target>
diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng
index 0dfb54d0..f7ceb578 100644
--- a/BUILD/Languages/spanish.lng
+++ b/BUILD/Languages/spanish.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>Examinar directorio</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Solicitud de aborto: Esperando a que la operación actual finalice...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Sincronización Automática</target>
+<source>Error</source>
+<target>Error</target>
+
<source>Select alternate comparison settings</source>
<target>Seleccionar opciones alternativas de comparación</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>Acerca de</target>
-<source>Error</source>
-<target>Error</target>
-
<source>Warning</source>
<target>Atención</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Código de error de Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Error al resolver enlace simbólico:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>No se puede resolver el enlace simbólico %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Error al leer de la base de datos de sincronización:</target>
+<source>Cannot read file %x.</source>
+<target>No se puede leer el archivo %x</target>
-<source>Error writing to synchronization database:</source>
-<target>Error al escribir en la base de datos de sincronización:</target>
+<source>Cannot write file %x.</source>
+<target>No se puede escribir el archivo %x</target>
-<source>Incompatible synchronization database format:</source>
-<target>Formato de base de datos de sincronización incompatible:</target>
+<source>Database file %x is incompatible.</source>
+<target>El archivo de base de datos %x es incompatible</target>
<source>Initial synchronization:</source>
<target>Sincronización inicial:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Uno de los archivos de la base de datos de FreeFileSync aún no existe:</target>
+<source>Database file %x does not yet exist.</source>
+<target>El archivo de base de datos %x aún no existe</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Archivos de base de datos no comparten la misma sesión de sincronización:</target>
+<source>Out of memory!</source>
+<target>¡Sin memoria!</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>
<source>An exception occurred!</source>
<target>¡Ha ocurrido una excepción!</target>
-<source>Error reading file attributes:</source>
-<target>Error al leer atributos del archivo:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>No se puede leer archivo de atributos de %x</target>
+
+<source>Cannot get process information.</source>
+<target>No se puede obtener información del proceso.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Esperando mientras el directorio se encuentre bloqueado (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Error al establecer bloqueo del directorio:</target>
+<source>Cannot set directory lock %x.</source>
+<target>No se puede establecer el directorio de bloqueo %x</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x segundos</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Error al leer archivo:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Error analizando archivo %x, fila %y, columna %z.</target>
<source>Scanning:</source>
<target>Escanear:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Hilos]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>¡Archivo de configuración de FreeFileSync inválido!</target>
+<source>/sec</source>
+<target>/seg</target>
-<source>Error parsing configuration file:</source>
-<target>Error al analizar el archivo de configuración:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>El archivo %x no contiene una configuración válida.</target>
-<source>Configuration loaded partially only:</source>
-<target>Configuración cargada sólo parcialmente:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Archivo de configuración %x cargado sólo parcialmente.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>¡Incapaz de mover %x a la Papelera de reciclaje!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>No se puede acceder al servicio de copia Volume Shadow.</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Por favor, use la versión de 64 bits de FreeFileSync para crear copias de Shadow en el sistema.</target>
<source>Cannot load file %x.</source>
<target>No se ha podido cargar el archivo %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>¡Error al acceder al servicio Volume Shadow Copy!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>La realización de copias shadow en WOW64 no está soportado. Por favor, use la versión 64-bit de FreeFileSync.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Incapaz de determinar nombre de volumen para el archivo:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>La ruta %x no contiene un nombre de volumen.</target>
<source>Volume name %x not part of file name %y!</source>
<target>El nombre del volumen %x no es una parte del nombre de archivo %y</target>
-<source>/sec</source>
-<target>/seg</target>
-
-<source>File does not exist:</source>
-<target>El archivo no existe:</target>
+<source>Cannot find file %x.</source>
+<target>No se puede encontrar el archivo %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Incapaz de leer los siguientes elementos XML:</target>
@@ -297,15 +300,18 @@ La línea de comandos se ejecuta cada vez:
<source>Start</source>
<target>Iniciar</target>
+<source>&Retry</source>
+<target>&Reintentar</target>
+
+<source>Cancel</source>
+<target>Cancelar</target>
+
<source>(Build: %x)</source>
<target>(Completado: %x)</target>
<source>RealtimeSync configuration</source>
<target>Configuración de RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>El archivo ya existe. ¿Quiere sobreescribirlo?</target>
-
<source>&Restore</source>
<target>&Restaurar</target>
@@ -322,7 +328,7 @@ La línea de comandos se ejecuta cada vez:
<target>Un campo de directorio está vacío.</target>
<source>Logging</source>
-<target>Iniciando sesión</target>
+<target>Registro</target>
<source>File time and size</source>
<target>Fecha y tamaño del archivo</target>
@@ -348,35 +354,38 @@ La línea de comandos se ejecuta cada vez:
<source>FreeFileSync configuration</source>
<target>Configuración de FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>Tarea por lotes de FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>¡Incapaz de crear un archivo de registro!</target>
-
<source>Batch execution</source>
<target>Ejecución por lotes</target>
-<source>Stop</source>
-<target>Detener</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>Synchronization aborted!</source>
<target>¡Sincronización abortada!</target>
<source>Synchronization completed with errors!</source>
<target>¡Sincronización completada con errores!</target>
+<source>Nothing to synchronize!</source>
+<target>¡Nada que sincronizar!</target>
+
<source>Synchronization completed successfully!</source>
<target>¡Sincronización completada con éxito!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Presionar "Cambiar" para abrir el modo GUI de FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Presione "Cambiar" para resolver los problemas en el diálogo principal de FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Cambiando al modo GUI de FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Cambiando al diálogo principal de FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>¡Incapaz de conectar con sourceforge.net!</target>
@@ -534,9 +543,6 @@ La línea de comandos se ejecuta cada vez:
<source>Items found:</source>
<target>Elementos encontrados:</target>
-<source>Items remaining:</source>
-<target>Elementos restantes:</target>
-
<source>Speed:</source>
<target>Velocidad:</target>
@@ -588,9 +594,6 @@ La línea de comandos se ejecuta cada vez:
<source>&Load</source>
<target>&Cargar</target>
-<source>&Cancel</source>
-<target>&Cancelar</target>
-
<source>Select variant:</source>
<target>Seleccione un tipo:</target>
@@ -639,8 +642,8 @@ La línea de comandos se ejecuta cada vez:
<source>Conflict/file cannot be categorized</source>
<target>Conflicto/el achivo no puede ser categorizado</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Comparar por...</target>
@@ -675,9 +678,6 @@ es el mismo
<source>Synchronizing...</source>
<target>Sincronizando...</target>
-<source>Items processed:</source>
-<target>Elementos procesados:</target>
-
<source>&Pause</source>
<target>&Pausa</target>
@@ -717,9 +717,6 @@ es el mismo
<source>&Ignore</source>
<target>&Ignorar</target>
-<source>&Retry</source>
-<target>&Reintentar</target>
-
<source>Do not show this dialog again</source>
<target>No volver a mostrar este diálogo</target>
@@ -1017,9 +1014,6 @@ Excluir: \stuff\temp\*
<source>File list exported!</source>
<target>¡Lista de archivos exportada!</target>
-<source>Error writing file:</source>
-<target>Error al escribir archivo:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Excluir: \stuff\temp\*
<source>Paused</source>
<target>Pausado</target>
+<source>Initializing...</source>
+<target>Inicializando...</target>
+
<source>Aborted</source>
<target>Abortado</target>
<source>Completed</source>
<target>Terminado</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Solicitud de aborto: Esperando a que la operación actual finalice...</target>
+<source>Continue</source>
+<target>Continuar</target>
<source>Pause</source>
<target>Pausa</target>
-<source>Continue</source>
-<target>Continuar</target>
-
<source>Cannot find %x</source>
<target>No se puede encontrar %x</target>
@@ -1218,65 +1212,65 @@ Excluir: \stuff\temp\*
<pluralform>%x días</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>No se ha podido inicializar la visualización de directorios:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Error al visualizar los directorios.</target>
+<source>Cannot monitor directory %x.</source>
+<target>No se puede monitorizar el directorio %x.</target>
<source>Conversion error:</source>
<target>Error de conversión:</target>
-<source>Error deleting file:</source>
-<target>Error al borrar archivo:</target>
+<source>Cannot delete file %x.</source>
+<target>No se puede eliminar el archivo %x.</target>
-<source>Error moving file:</source>
-<target>Error al mover archivo:</target>
+<source>The file is locked by another process:</source>
+<target>El archivo está bloqueado por otro proceso:</target>
-<source>Target file already existing!</source>
-<target>¡El archivo de destino ya existe!</target>
+<source>Cannot move file %x to %y.</source>
+<target>No se puede mover el archivo %x a %y.</target>
-<source>Error moving directory:</source>
-<target>Error al mover directorio:</target>
+<source>Cannot delete directory %x.</source>
+<target>No se puede eliminar el directorio %x.</target>
-<source>Target directory already existing!</source>
-<target>¡El directorio de destino ya existe!</target>
+<source>Cannot write modification time of %x.</source>
+<target>No se puede escribir el tiempo de modificación de %x.</target>
-<source>Error deleting directory:</source>
-<target>Error al borrar directorio:</target>
+<source>Cannot find system function %x.</source>
+<target>No se puede encontrar la función del sistema %x.</target>
-<source>Error changing modification time:</source>
-<target>Error al cambiar hora de modificación:</target>
+<source>Cannot read security context of %x.</source>
+<target>No se puede leer el contexto de seguridad de %x.</target>
-<source>Error loading library function:</source>
-<target>Error al cargar la función de biblioteca:</target>
+<source>Cannot write security context of %x.</source>
+<target>No se puede escribir el contexto de seguridad de %x.</target>
-<source>Error reading security context:</source>
-<target>Error al leer en contexto de seguridad:</target>
+<source>Cannot read permissions of %x.</source>
+<target>No se pueden leer los permisos de %x.</target>
-<source>Error writing security context:</source>
-<target>Error al escribir en contexto de seguridad:</target>
+<source>Cannot write permissions of %x.</source>
+<target>No se pueden escribir los permisos de %x.</target>
-<source>Error copying file permissions:</source>
-<target>Error al copiar permisos del fichero:</target>
+<source>Cannot create directory %x.</source>
+<target>No se puede crear el directorio %x.</target>
-<source>Error creating directory:</source>
-<target>Error al crear directorio:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>No se puede copiar el enlance simbólico %x a %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Error al copiar enlace simbólico:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>No se pueden escribir los atributos de archivo de %x.</target>
-<source>Error copying file:</source>
-<target>Error al copiar archivo:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>No se puede copiar el archivo %x a %y.</target>
-<source>Error traversing directory:</source>
-<target>Error al buscar en el directorio:</target>
+<source>Cannot read directory %x.</source>
+<target>No se puede leer el directorio %x.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Bucle infinito al buscar en el directorio:</target>
+<source>Endless loop.</source>
+<target>Bucle infinito.</target>
-<source>Error setting privilege:</source>
-<target>Error al establecer privilegios:</target>
+<source>Cannot set privilege %x.</source>
+<target>No se puede</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>¡Incapaz de mover %x a la Papelera de reciclaje!</target>
<source>Both sides have changed since last synchronization!</source>
<target>¡Ambos lados han cambiado desde la última sincronizacion!</target>
@@ -1302,8 +1296,8 @@ Excluir: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Puede ignorar este error al considerar el directorio como vacío.</target>
-<source>Directory does not exist:</source>
-<target>El directorio no existe:</target>
+<source>Cannot find directory %x.</source>
+<target>No se puede encontrar el directorio %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>¡Los directorios son dependientes! Tenga cuidado al establecer las reglas de sincronización:</target>
@@ -1311,20 +1305,17 @@ Excluir: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Preparando sincronización...</target>
-<source>Out of memory!</source>
-<target>¡Sin memoria!</target>
+<source>Conflict detected:</source>
+<target>Conflicto detectado:</target>
<source>File %x has an invalid date!</source>
<target>¡El archivo %x tiene una fecha inválida!</target>
-<source>Conflict detected:</source>
-<target>Conflicto detectado:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>¡Los archivos %x tienen la misma fecha pero un tamaño diferente!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>¡Los enlaces simbólicos %x tienen la misma fecha pero un destino diferente!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Los enlaces simbólicos %x tienen la misma fecha pero un destino diferente.</target>
<source>Comparing content of files %x</source>
<target>Comparación del contenido de los archivos %x</target>
@@ -1407,12 +1398,12 @@ Excluir: \stuff\temp\*
<source>Creating file %x</source>
<target>Creando archivo %x</target>
-<source>Creating folder %x</source>
-<target>Creando carpeta %x</target>
-
<source>Creating symbolic link %x</source>
<target>Creando enlace simbólico %x</target>
+<source>Creating folder %x</source>
+<target>Creando carpeta %x</target>
+
<source>Overwriting file %x</source>
<target>Sobreescribir archivo %x</target>
@@ -1431,8 +1422,8 @@ Excluir: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>¡El directorio para el versionamiento de archivo no ha sido especificado!</target>
-<source>Source directory does not exist anymore:</source>
-<target>El directorio origen ya no existe:</target>
+<source>Source directory %x not found.</source>
+<target>Directorio fuente %x no encontrado.</target>
<source>Unresolved conflicts existing!</source>
<target>¡Existen conflictos sin resolver!</target>
@@ -1467,12 +1458,6 @@ Excluir: \stuff\temp\*
<source>Generating database...</source>
<target>Generando base de datos...</target>
-<source>Nothing to synchronize!</source>
-<target>¡Nada que sincronizar!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>¡Incapaz de copiar el archivo bloqueado %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Error de verificación de datos: ¡Los archivos de origen y destino tienen un contenido diferente!</target>
diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng
index 1e59759d..06a0b627 100644
--- a/BUILD/Languages/swedish.lng
+++ b/BUILD/Languages/swedish.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Sök upp katalog</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Avbryter: Väntar på att aktuell process skall slutföras...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatiserad synkronisering</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Felkod %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Kan inte tyda symbolisk länk:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Den symboliska länken %x kan inte matchas.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Byte</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Kan inte läsa från databasen:</target>
+<source>Cannot read file %x.</source>
+<target>Filen %x kan inte läsas in</target>
-<source>Error writing to synchronization database:</source>
-<target>Kan inte skriva till databas:</target>
+<source>Cannot write file %x.</source>
+<target>Filen %x kan inte skrivas</target>
-<source>Incompatible synchronization database format:</source>
-<target>Inkompatibelt databasformat:</target>
+<source>Database file %x is incompatible.</source>
+<target>Databasfilen %x är inkompatibel</target>
<source>Initial synchronization:</source>
<target>Initial synkronisering:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>En av FreeFileSyncs databasfiler saknas:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Databasfilen %x finns ännu inte</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Databasfiler delar inte en gemensam synkroniseringssession:</target>
+<source>Out of memory!</source>
+<target>Minnesbrist!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Databasfilerna har ingen gemensam session</target>
<source>An exception occurred!</source>
<target>Ett undantag inträffade!</target>
-<source>Error reading file attributes:</source>
-<target>Kan inte läsa filattribut:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Kan inte läsa filattribut för %x</target>
+
+<source>Cannot get process information.</source>
+<target>Processinformation kan inte inhämtas</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Väntar medan katalogen låses (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Kan inte låsa katalogen:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Kan inte låsa katalogen %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x sek</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Kan inte läsa filen:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Tolkningsfel på filen %x, rad %y, kolumn %z.</target>
<source>Scanning:</source>
<target>Skannar:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x trådar]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Felaktig FreeFileSync konfigurationsfil!</target>
+<source>/sec</source>
+<target>/s</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>Filen %x innehåller ingen giltig konfiguration.</target>
-<source>Error parsing configuration file:</source>
-<target>Kan inte läsa in konfigurationsfil:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Konfigurationsfilen %x lästes bara delvis in.</target>
-<source>Configuration loaded partially only:</source>
-<target>Konfigurationsfilen endast delvis inläst</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Kan inte komma åt tjänsten Volume Shadow Copy.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Kan inte flytta %x till Papperskorgen</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Använd FreeFileSync 64-bitarsversion för att skapa skuggkopior på detta system.</target>
<source>Cannot load file %x.</source>
<target>Kan inte läsa in %x</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Kunde inte starta tjänsten Volume Shadow Copy (VSS)</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Skuggkopior av wow64 stöds ej. Använd FreeFileSync x64 istället!</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Kan inte bestämma volymnamn för filen:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>Sökvägen %x innehåller inget volymnamn.</target>
<source>Volume name %x not part of file name %y!</source>
<target>Volymnamn %x saknas i filnamn %y!</target>
-<source>/sec</source>
-<target>/s</target>
-
-<source>File does not exist:</source>
-<target>Filen finns inte:</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>
@@ -303,9 +306,6 @@ Kommandot verkställes när:
<source>RealtimeSync configuration</source>
<target>RealtimeSync konfiguration</target>
-<source>File already exists. Overwrite?</source>
-<target>Filen finns redan. Vill du skriva över:</target>
-
<source>&Restore</source>
<target>&Återställ</target>
@@ -348,35 +348,38 @@ Kommandot verkställes när:
<source>FreeFileSync configuration</source>
<target>FreeFileSync konfiguration</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Batch-jobb</target>
-
-<source>Unable to create log file!</source>
-<target>Kan inte skapa loggfil!</target>
-
<source>Batch execution</source>
<target>Batch-körning</target>
-<source>Stop</source>
-<target>Stopp</target>
+<source>Items processed:</source>
+<target>Processade poster</target>
+
+<source>Items remaining:</source>
+<target>Återstående poster:</target>
<source>Total time:</source>
<target>Total tid:</target>
+<source>Stop</source>
+<target>Stopp</target>
+
<source>Synchronization aborted!</source>
<target>Synkronisering avbruten!</target>
<source>Synchronization completed with errors!</source>
<target>Synkronisering slutförd med fel!</target>
+<source>Nothing to synchronize!</source>
+<target>Det finns inget att synkronisera!</target>
+
<source>Synchronization completed successfully!</source>
<target>Synkronisering slutförd!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>Tryck på "Växla" för att öppna FreeFileSyncs grafiska läge</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>Tryck "Växla" för att lösa problem i FreeFileSyncs huvudfönster</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Växlar till FreeFileSyncs grafiska läge</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Växlar till FreeFileSyncs huvudfönster...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Kan inte ansluta sourceforge.net!</target>
@@ -534,9 +537,6 @@ Kommandot verkställes när:
<source>Items found:</source>
<target>Funna poster:</target>
-<source>Items remaining:</source>
-<target>Återstående poster:</target>
-
<source>Speed:</source>
<target>Hastighet:</target>
@@ -564,9 +564,6 @@ Kommandot verkställes när:
<source>Right</source>
<target>Höger</target>
-<source>Sync setttings</source>
-<target>Synkroniseringsinställningar</target>
-
<source>Status feedback</source>
<target>Status</target>
@@ -591,8 +588,8 @@ Kommandot verkställes när:
<source>&Load</source>
<target>&Läs in</target>
-<source>&Cancel</source>
-<target>&Avbryt</target>
+<source>Cancel</source>
+<target>Avbryt</target>
<source>Select variant:</source>
<target>Välj variant:</target>
@@ -642,8 +639,8 @@ Kommandot verkställes när:
<source>Conflict/file cannot be categorized</source>
<target>Konflikt/Fil kan inte kategoriseras</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Jämför...</target>
@@ -678,9 +675,6 @@ Filerna betecknas som lika om,
<source>Synchronizing...</source>
<target>Synkroniserar...</target>
-<source>Items processed:</source>
-<target>Processade poster</target>
-
<source>&Pause</source>
<target>&Paus</target>
@@ -1020,9 +1014,6 @@ Undanta: \stuff\temp\*
<source>File list exported!</source>
<target>Fillista exporterad!</target>
-<source>Error writing file:</source>
-<target>Kan inte skriva fil:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1068,21 +1059,21 @@ Undanta: \stuff\temp\*
<source>Paused</source>
<target>Pausad</target>
+<source>Initializing...</source>
+<target>Initierar...</target>
+
<source>Aborted</source>
<target>Användaren avbröt</target>
<source>Completed</source>
<target>Slutförd</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Avbryter: Väntar på att aktuell process skall slutföras...</target>
+<source>Continue</source>
+<target>Fortsätt</target>
<source>Pause</source>
<target>Paus</target>
-<source>Continue</source>
-<target>Fortsätt</target>
-
<source>Cannot find %x</source>
<target>Kan inte hitta %x</target>
@@ -1221,68 +1212,65 @@ Undanta: \stuff\temp\*
<pluralform>%x dagar</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Kan inte initiera katalogskanner:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Fel vid övervakning av kataloger.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Katalogen %x kan inte övervakas.</target>
<source>Conversion error:</source>
<target>Konversionsfel:</target>
-<source>Error deleting file:</source>
-<target>Kan inte ta bort fil:</target>
+<source>Cannot delete file %x.</source>
+<target>Filen %x kan inte tas bort.</target>
-<source>Error moving file:</source>
-<target>Kan inte flytta fil:</target>
+<source>The file is locked by another process:</source>
+<target>Filen är låst av en annan process:</target>
-<source>Target file already existing!</source>
-<target>Filen finns redan!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Kan inte flytta filen %x till %y.</target>
-<source>Error moving directory:</source>
-<target>Kan inte flytta katalog:</target>
+<source>Cannot delete directory %x.</source>
+<target>Kan inte ta bort katalogen %x.</target>
-<source>Target directory already existing!</source>
-<target>MÃ¥lkatalogen finns redan!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Kan inte ändra tidsangivelsen för %x.</target>
-<source>Error deleting directory:</source>
-<target>Kan inte ta bort katalog:</target>
+<source>Cannot find system function %x.</source>
+<target>Kan inte hitta systemfunktion %x</target>
-<source>Error changing modification time:</source>
-<target>Kan inte modifiera tidsstämpel:</target>
+<source>Cannot read security context of %x.</source>
+<target>Kan inte läsa säkerhetskontext för %x.</target>
-<source>Error loading library function:</source>
-<target>Kan inte starta biblioteksfunktion:</target>
+<source>Cannot write security context of %x.</source>
+<target>Kan inte skriva säkerhetskontext för %x.</target>
-<source>Error reading security context:</source>
-<target>Kan inte läsa säkerhetskontext:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Kan inte läsa behörigheter för %x.</target>
-<source>Error writing security context:</source>
-<target>Kan inte skriva säkerhetskontext:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Kan inte skriva behörigheter för %x.</target>
-<source>Error copying file permissions:</source>
-<target>Kan inte kopiera filsystembehörighet:</target>
+<source>Cannot create directory %x.</source>
+<target>Kan inte skapa katalogen %x.</target>
-<source>Error creating directory:</source>
-<target>Kan inte skapa katalog:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Kan inte kopiera den symboliska länken %x till %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Kan inte kopiera symbolisk länk:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan inte skriva filattribut för %x.</target>
-<source>Error copying file:</source>
-<target>Kan inte kopiera fil:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Kan inte kopiera filen %x till %y.</target>
-<source>Error opening file:</source>
-<target>Kan inte öppna fil:</target>
+<source>Cannot read directory %x.</source>
+<target>Kan inte läsa in katalogen %x.</target>
-<source>Error traversing directory:</source>
-<target>Accessfel på katalog:</target>
+<source>Endless loop.</source>
+<target>Oändlig loop.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Oändlig loop vid accessförsök på katalog:</target>
+<source>Cannot set privilege %x.</source>
+<target>Kan inte att ange behörigheten %x.</target>
-<source>Error setting privilege:</source>
-<target>Kan inte ange privilegie:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Kan inte flytta %x till Papperskorgen</target>
<source>Both sides have changed since last synchronization!</source>
<target>Båda sidor har ändrats sedan senaste synkroniseringen!</target>
@@ -1308,8 +1296,8 @@ Undanta: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Du kan bortse från det här felet och utgå ifrån att katalogen är tom</target>
-<source>Directory does not exist:</source>
-<target>Katalogen finns inte:</target>
+<source>Cannot find directory %x.</source>
+<target>Kan inte hitta katalogen %x.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Kataloger är beroende! Var försiktig när du sätter upp synkroniseringsregler:</target>
@@ -1317,20 +1305,17 @@ Undanta: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Förbereder synkronisering...</target>
-<source>Out of memory!</source>
-<target>Minnesbrist!</target>
+<source>Conflict detected:</source>
+<target>Konflikt upptäckt:</target>
<source>File %x has an invalid date!</source>
<target>Filen %x har ett ogiltigt datum!</target>
-<source>Conflict detected:</source>
-<target>Konflikt upptäckt:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Filerna %x har samma datum men olika storlek!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Symbolisk länk %x har samma datum, men annat mål!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>De symboliska länkarna %x har samma datumstämpel men olika mål.</target>
<source>Comparing content of files %x</source>
<target>Jämför filinnehåll för %x</target>
@@ -1413,12 +1398,12 @@ Undanta: \stuff\temp\*
<source>Creating file %x</source>
<target>Skapar fil %x</target>
-<source>Creating folder %x</source>
-<target>Skapar katalog %x</target>
-
<source>Creating symbolic link %x</source>
<target>Skapar den symboliska länken %x</target>
+<source>Creating folder %x</source>
+<target>Skapar katalog %x</target>
+
<source>Overwriting file %x</source>
<target>Skriver över filen %x</target>
@@ -1437,8 +1422,8 @@ Undanta: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Katalog för versionshantering har inte specificerats</target>
-<source>Source directory does not exist anymore:</source>
-<target>Källkatalogen finns inte längre:</target>
+<source>Source directory %x not found.</source>
+<target>Källkatalogen %x hittas inte</target>
<source>Unresolved conflicts existing!</source>
<target>Obehandlad konflikt upptäckt!</target>
@@ -1473,12 +1458,6 @@ Undanta: \stuff\temp\*
<source>Generating database...</source>
<target>Skapar databas...</target>
-<source>Nothing to synchronize!</source>
-<target>Det finns inget att synkronisera!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Kan inte kopiera den låsta filen %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Verifikationsfel: Källfil och målfil har olika innehåll!</target>
diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng
index 7d6ef2ce..5a440333 100644
--- a/BUILD/Languages/turkish.lng
+++ b/BUILD/Languages/turkish.lng
@@ -19,6 +19,9 @@
<source>Browse directory</source>
<target>Klasöre gözat</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Vazgeçildi: Yürürlükteki işlemin bitmesi bekleniyor...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - KendiliÄŸinden EÅŸleÅŸtirme</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Linux Hata Kodu %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Sembolik bağlantı çözümlenirken hata:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>%x simge bağlantısı çözümlenemedi</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -136,35 +139,41 @@
<pluralform>%x Bayt</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Eşleştirme veri tabanı okunurken hata:</target>
+<source>Cannot read file %x.</source>
+<target>%x dosyası okunamadı.</target>
-<source>Error writing to synchronization database:</source>
-<target>Eşleştirme veri tabanına yazılırken hata:</target>
+<source>Cannot write file %x.</source>
+<target>%x dosyası yazılamadı.</target>
-<source>Incompatible synchronization database format:</source>
-<target>Uyumsuz eşleştirme veritabanı biçimi:</target>
+<source>Database file %x is incompatible.</source>
+<target>%x veritabanı dosyası uyumsuz</target>
<source>Initial synchronization:</source>
<target>Başlangıç eşleştirmesi:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>FreeFileSync veritabanı dosyalarından biri henüz yok:</target>
+<source>Database file %x does not yet exist.</source>
+<target>%x veritabanı dosyası henüz yok.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Veritabanıdosyaları ortak bir eşleştirmeoturumunu paylaşmıyor:</target>
+<source>Out of memory!</source>
+<target>Bellek yetersiz!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Veritabanı dosyaları ortak bir oturumu paylaşamaz.</target>
<source>An exception occurred!</source>
<target>Olağan dışı bir durum oluştu!</target>
-<source>Error reading file attributes:</source>
-<target>Dosya öznitelikleri okunurken hata:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>%x dosyasının özellikleri okunamadı.</target>
+
+<source>Cannot get process information.</source>
+<target>İşlem bilgisi alınamadı.</target>
<source>Waiting while directory is locked (%x)...</source>
<target>Klasör kilitli olduğundan bekleniyor (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Klasör kilitlenirken hata:</target>
+<source>Cannot set directory lock %x.</source>
+<target>%x klasörü kilitlenemedi.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -175,8 +184,8 @@
<pluralform>%x saniye</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Dosya okunurken hata:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>%x dosyası işlenirken hata, satır %y, sütun %z.</target>
<source>Scanning:</source>
<target>Taranıyor:</target>
@@ -193,38 +202,32 @@
<pluralform>[%x Ä°ÅŸ]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Geçersiz FreeFileSync yapılandırma dosyası!</target>
+<source>/sec</source>
+<target>/san</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>%x dosyası geçerli bir yapılandırma bilgisi içermiyor.</target>
-<source>Error parsing configuration file:</source>
-<target>Yapılandırma dosyası çözümlenirken hata:</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>%x yapılandırma dosyası tamamen yüklenemedi.</target>
-<source>Configuration loaded partially only:</source>
-<target>Yapılandırma yalnız kısmen yüklendi:</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Birim Gölge Kopya hizmetine erişilemedi.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>%x Geri Dönüşüm Kutusuna gönderilemedi</target>
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Bu sistem üzerinde gölge kopyalar oluşturmak için FreeFileSync 64-bit sürümünü kullanın.</target>
<source>Cannot load file %x.</source>
<target>%x dosyası yüklenemedi.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Gölge Kopya Hizmetine erişilirken hata oldu!</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>WOW64 üzerinde gölge kopyalama desteklenmiyor. FreeFileSync 64-bit sürümünü kullanın</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Dosya için birim adı belirlenemedi:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>%x yolu bir birim adı içermiyor.</target>
<source>Volume name %x not part of file name %y!</source>
<target>%x birim adı, %y dosya adının parçası değil!</target>
-<source>/sec</source>
-<target>/san</target>
-
-<source>File does not exist:</source>
-<target>Dosya bulunamadı:</target>
+<source>Cannot find file %x.</source>
+<target>%x dosyası bulunamadı.</target>
<source>Cannot read the following XML elements:</source>
<target>Şu XML elemanları okunamadı:</target>
@@ -303,9 +306,6 @@ Her seferinde çalıştırılacak komut satırı:
<source>RealtimeSync configuration</source>
<target>RealtimeSync yapılandırması</target>
-<source>File already exists. Overwrite?</source>
-<target>Dosya zaten var. Üzerine yazılsın mı?</target>
-
<source>&Restore</source>
<target>Ge&ri yükle</target>
@@ -348,35 +348,38 @@ Her seferinde çalıştırılacak komut satırı:
<source>FreeFileSync configuration</source>
<target>FreeFileSync yapılandırması</target>
-<source>FreeFileSync Batch Job</source>
-<target>FreeFileSync Toplu Ä°ÅŸi</target>
-
-<source>Unable to create log file!</source>
-<target>Günlük dosyası oluşturulamıyor!</target>
-
<source>Batch execution</source>
<target>Toplu komut yürütme</target>
-<source>Stop</source>
-<target>Durdur</target>
+<source>Items processed:</source>
+<target>Ä°ÅŸlenen bileÅŸenler:</target>
+
+<source>Items remaining:</source>
+<target>Kalan bileÅŸenler:</target>
<source>Total time:</source>
<target>Toplam zaman:</target>
+<source>Stop</source>
+<target>Durdur</target>
+
<source>Synchronization aborted!</source>
<target>EÅŸleÅŸtirme durduruldu!</target>
<source>Synchronization completed with errors!</source>
<target>Eşleştirme hatalarla tamamlandı!</target>
+<source>Nothing to synchronize!</source>
+<target>EÅŸleÅŸtirilecek bir ÅŸey yok!</target>
+
<source>Synchronization completed successfully!</source>
<target>Eşleştirme sorunsuz tamamlandı!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>FreeFileSync grafik kullanıcı arayüzünü açmak için "Geç" düğmesine tıklayın</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>FreeFileSync ana penceresindeki sorunları çözmek için "Değiştir" düğmesine tıklayın.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>FreeFileSync grafik kullanıcı arayüzüne geçiliyor...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>FreeFileSync ana penceresine geçiliyor...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>sourceforge.net sitesine bağlanılamıyor!</target>
@@ -534,9 +537,6 @@ Her seferinde çalıştırılacak komut satırı:
<source>Items found:</source>
<target>Bulunan bileÅŸenler:</target>
-<source>Items remaining:</source>
-<target>Kalan bileÅŸenler:</target>
-
<source>Speed:</source>
<target>Hız:</target>
@@ -588,8 +588,8 @@ Her seferinde çalıştırılacak komut satırı:
<source>&Load</source>
<target>Yük&le</target>
-<source>&Cancel</source>
-<target>Ä°&ptal</target>
+<source>Cancel</source>
+<target>Ä°ptal</target>
<source>Select variant:</source>
<target>Davranışı seçin:</target>
@@ -639,8 +639,8 @@ Her seferinde çalıştırılacak komut satırı:
<source>Conflict/file cannot be categorized</source>
<target>Çatışma/dosya kategorize edilemedi</target>
-<source>&OK</source>
-<target>&Tamam</target>
+<source>OK</source>
+<target>Tamam</target>
<source>Compare by...</source>
<target>Karşılaştırma ölçütünü seçin:</target>
@@ -675,9 +675,6 @@ aynı olmalıdır
<source>Synchronizing...</source>
<target>EÅŸleÅŸtiriliyor...</target>
-<source>Items processed:</source>
-<target>Ä°ÅŸlenen bileÅŸenler:</target>
-
<source>&Pause</source>
<target>&Duraklat</target>
@@ -1017,9 +1014,6 @@ Katma: \stuff\temp\*
<source>File list exported!</source>
<target>Dosya listesi verilmiÅŸ!</target>
-<source>Error writing file:</source>
-<target>Dosya yazılırken hata:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1065,21 +1059,21 @@ Katma: \stuff\temp\*
<source>Paused</source>
<target>Duraklatıldı</target>
+<source>Initializing...</source>
+<target>Başlatılıyor...</target>
+
<source>Aborted</source>
<target>Vazgeçildi</target>
<source>Completed</source>
<target>Tamamlandı</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Vazgeçildi: Yürürlükteki işlemin bitmesi bekleniyor...</target>
+<source>Continue</source>
+<target>Devam et</target>
<source>Pause</source>
<target>Duraklat</target>
-<source>Continue</source>
-<target>Devam et</target>
-
<source>Cannot find %x</source>
<target>%x bulunamadı</target>
@@ -1218,65 +1212,65 @@ Katma: \stuff\temp\*
<pluralform>%x gün</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Klasör izlemesi başlatılamadı:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Klasörler izlenirken hata.</target>
+<source>Cannot monitor directory %x.</source>
+<target>%x klasörü izlenemiyor.</target>
<source>Conversion error:</source>
<target>Dönüştürme hatası:</target>
-<source>Error deleting file:</source>
-<target>Dosya silinirken hata:</target>
+<source>Cannot delete file %x.</source>
+<target>%x dosyası silinemiyor.</target>
+
+<source>The file is locked by another process:</source>
+<target>Dosya başka bir işlem tarafından kilitlenmiş:</target>
-<source>Error moving file:</source>
-<target>Dosya taşınırken hata:</target>
+<source>Cannot move file %x to %y.</source>
+<target>%x dosyası %y olarak taşınamadı.</target>
-<source>Target file already existing!</source>
-<target>Hedef dosya zaten var!</target>
+<source>Cannot delete directory %x.</source>
+<target>%x klasörü silinemedi.</target>
-<source>Error moving directory:</source>
-<target>Klasör taşınırken hata:</target>
+<source>Cannot write modification time of %x.</source>
+<target>%x son değişiklik zamanı yazılamadı.</target>
-<source>Target directory already existing!</source>
-<target>Hedef klasör zaten var!</target>
+<source>Cannot find system function %x.</source>
+<target>%x sistem işlevi bulunamadı.</target>
-<source>Error deleting directory:</source>
-<target>Klasör silinirken hata:</target>
+<source>Cannot read security context of %x.</source>
+<target>%x için güvenlik bağlamı okunamadı.</target>
-<source>Error changing modification time:</source>
-<target>DeÄŸiÅŸiklik tarihini deÄŸiÅŸtirirken hata:</target>
+<source>Cannot write security context of %x.</source>
+<target>%x için güvenlik bağlamı yazılamadı.</target>
-<source>Error loading library function:</source>
-<target>Kütüphane işlevi yüklenirken hata:</target>
+<source>Cannot read permissions of %x.</source>
+<target>%x izinleri okunamadı.</target>
-<source>Error reading security context:</source>
-<target>Güüvenlik bağlamı okunurken hata:</target>
+<source>Cannot write permissions of %x.</source>
+<target>%x izinleri yazılamadı.</target>
-<source>Error writing security context:</source>
-<target>Güvenlik bağlamı yazılırken hata:</target>
+<source>Cannot create directory %x.</source>
+<target>%x dosyası oluşturulamadı.</target>
-<source>Error copying file permissions:</source>
-<target>Dosya izinleri kopyalanırken hata:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>%x simgesel bağlantısı %y olarak kopyalanamadı.</target>
-<source>Error creating directory:</source>
-<target>Klasör oluşturulurken hata:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%x dosya öznitelikleri yazılamadı.</target>
-<source>Error copying symbolic link:</source>
-<target>Sembolik bağlantı kopyalanırken hata:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>%x dosyası %y olarak kopyalanamadı.</target>
-<source>Error copying file:</source>
-<target>Dosya kopyalanırken hata:</target>
+<source>Cannot read directory %x.</source>
+<target>%x klasörü okunamadı.</target>
-<source>Error traversing directory:</source>
-<target>Klasörde dolaşırken hata:</target>
+<source>Endless loop.</source>
+<target>Sonsuz çevrim.</target>
-<source>Endless loop when traversing directory:</source>
-<target>Klasörlerde dolaşırken sonsuz döngü:</target>
+<source>Cannot set privilege %x.</source>
+<target>%x izni verilemedi.</target>
-<source>Error setting privilege:</source>
-<target>İzinler ayarlanırken hata:</target>
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>%x Geri Dönüşüm Kutusuna gönderilemedi</target>
<source>Both sides have changed since last synchronization!</source>
<target>Son eşleştirmeden bu yana iki yanın içeriği de değişmiş!</target>
@@ -1302,8 +1296,8 @@ Katma: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Bu hatayı, klasörü boş sayacak şekilde yok sayabilirsiniz.</target>
-<source>Directory does not exist:</source>
-<target>Klasör bulunamadı:</target>
+<source>Cannot find directory %x.</source>
+<target>%x klasörü bulunamadı.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Klasörler bağımlı! Eşleştirme kurallarını koyarken dikkatli olun:</target>
@@ -1311,20 +1305,17 @@ Katma: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Eşleştirmeye hazırlanıyor...</target>
-<source>Out of memory!</source>
-<target>Bellek yetersiz!</target>
+<source>Conflict detected:</source>
+<target>Çelişki bulundu:</target>
<source>File %x has an invalid date!</source>
<target>%x dosyasının tarihi geçersiz!</target>
-<source>Conflict detected:</source>
-<target>Çelişki bulundu:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>%x dosyalarının tarihleri aynı fakat boyutları farklı!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Sembolik bağlantılar %x aynı tarihli fakat hedefleri farklı!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>%x simgesel bağlantıları aynı tarihe sahip ancak hedef yolları farklı.</target>
<source>Comparing content of files %x</source>
<target>%x dosyalarının içeriği karşılaştırılıyor</target>
@@ -1407,12 +1398,12 @@ Katma: \stuff\temp\*
<source>Creating file %x</source>
<target>%x dosyası oluşturuluyor</target>
-<source>Creating folder %x</source>
-<target>%x klasörü oluşturuluyor</target>
-
<source>Creating symbolic link %x</source>
<target>%x sembolik bağlantısı oluşturuluyor</target>
+<source>Creating folder %x</source>
+<target>%x klasörü oluşturuluyor</target>
+
<source>Overwriting file %x</source>
<target>%x dosyasının üzerine yazılıyor</target>
@@ -1431,8 +1422,8 @@ Katma: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Dosya sürümlemesi için klasör desteklenmiyor!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Kaynak klasör artık yok:</target>
+<source>Source directory %x not found.</source>
+<target>%x kaynak klasörü bulunamadı.</target>
<source>Unresolved conflicts existing!</source>
<target>Çözülmemiş tutarsızlıklar var!</target>
@@ -1467,12 +1458,6 @@ Katma: \stuff\temp\*
<source>Generating database...</source>
<target>Veri tabanı oluşturuluyor...</target>
-<source>Nothing to synchronize!</source>
-<target>EÅŸleÅŸtirilecek bir ÅŸey yok!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>%x dosyası kilitli olduğundan kopyalanamıyor!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Veri doğrulama hatası: Kaynak ve hedef dosyası içeriği farklı!</target>
diff --git a/BUILD/Languages/ukrainian.lng b/BUILD/Languages/ukrainian.lng
index 6ee50ff3..5eadfddd 100644
--- a/BUILD/Languages/ukrainian.lng
+++ b/BUILD/Languages/ukrainian.lng
@@ -19,9 +19,15 @@
<source>Browse directory</source>
<target>ПереглÑнути каталог</target>
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>Запит перериваннÑ: Ð’ очікуванні Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— операції...</target>
+
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Ðвтоматична ÑинхронізаціÑ</target>
+<source>Error</source>
+<target>Помилка</target>
+
<source>Select alternate comparison settings</source>
<target>Вибрати альтернативні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ€Ñ–Ð²Ð½ÑннÑ</target>
@@ -52,9 +58,6 @@
<source>About</source>
<target>Про</target>
-<source>Error</source>
-<target>Помилка</target>
-
<source>Warning</source>
<target>Увага</target>
@@ -115,8 +118,8 @@
<source>Linux Error Code %x:</source>
<target>Код помилки Linux %x:</target>
-<source>Error resolving symbolic link:</source>
-<target>Помилка при вирішені Ñимволічного поÑиланнÑ:</target>
+<source>Cannot resolve symbolic link %x.</source>
+<target>Ðе вдаєтьÑÑ Ð²Ð¸Ñ€Ñ–ÑˆÐ¸Ñ‚Ð¸ Ñимвольне поÑÐ¸Ð»Ð°Ð½Ð½Ñ %x.</target>
<source>%x MB</source>
<target>%x МБ</target>
@@ -137,35 +140,41 @@
<pluralform>%x байтів</pluralform>
</target>
-<source>Error reading from synchronization database:</source>
-<target>Помилка при читанні з бази даних Ñинхронізації:</target>
+<source>Cannot read file %x.</source>
+<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл %x.</target>
-<source>Error writing to synchronization database:</source>
-<target>Помилка при запиÑÑ– у базу данних Ñинхронізації:</target>
+<source>Cannot write file %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð°Ð¿Ð¸Ñати файл %x.</target>
-<source>Incompatible synchronization database format:</source>
-<target>ÐеÑуміÑний формат бази даних Ñинхронізації:</target>
+<source>Database file %x is incompatible.</source>
+<target>ÐеÑуміÑний файл бази даних %x.</target>
<source>Initial synchronization:</source>
<target>Ð’Ñтупна ÑинхронізаціÑ:</target>
-<source>One of the FreeFileSync database files is not yet existing:</source>
-<target>Файлу бази даних FreeFileSync ще не Ñ–Ñнує:</target>
+<source>Database file %x does not yet exist.</source>
+<target>Файл бази даних %x ще не Ñ–Ñнує.</target>
-<source>Database files do not share a common synchronization session:</source>
-<target>Файли бази даних не мають Ñпільної ÑеÑÑ–Ñ— Ñинхронізації</target>
+<source>Out of memory!</source>
+<target>Бракує пам'ÑÑ‚Ñ–!</target>
+
+<source>Database files do not share a common session.</source>
+<target>Файли баз даних не поділÑÑŽÑ‚ÑŒ Ñпільну ÑеÑÑ–ÑŽ.</target>
<source>An exception occurred!</source>
<target>ВідбулоÑÑŒ виключеннÑ!</target>
-<source>Error reading file attributes:</source>
-<target>Помилка при читанні параметрів файлу:</target>
+<source>Cannot read file attributes of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ атрибути файла %Ñ….</target>
+
+<source>Cannot get process information.</source>
+<target>Ðе вдаєтьÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ інформацію процеÑу</target>
<source>Waiting while directory is locked (%x)...</source>
<target>ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð½ÑÑ‚Ñ‚Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð· каталогу (%x)...</target>
-<source>Error setting directory lock:</source>
-<target>Помилка Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ:</target>
+<source>Cannot set directory lock %x.</source>
+<target>Ðе вдаєтьÑÑ Ð²Ñтановити Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° %Ñ….</target>
<source>
<pluralform>1 sec</pluralform>
@@ -177,8 +186,8 @@
<pluralform>%x Ñек</pluralform>
</target>
-<source>Error reading file:</source>
-<target>Помилка при читанні файлу:</target>
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>Помилка розбору файла %x, Ñ€Ñдок %y, колонка %z.</target>
<source>Scanning:</source>
<target>Сканую:</target>
@@ -196,38 +205,32 @@
<pluralform>[%x Ðитей виконаннÑ]</pluralform>
</target>
-<source>Invalid FreeFileSync config file!</source>
-<target>Ðеправильний файл конфігурації FreeFileSync!</target>
+<source>/sec</source>
+<target>/Ñек</target>
-<source>Error parsing configuration file:</source>
-<target>Помилка при анализі файлу налаштувань Ñинхронізації:</target>
+<source>File %x does not contain a valid configuration.</source>
+<target>Файл %x не міÑтить правильної конфігурації.</target>
-<source>Configuration loaded partially only:</source>
-<target>ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð° лише чаÑтково</target>
+<source>Configuration file %x loaded partially only.</source>
+<target>Файл конфігурації %x завантажено лише чаÑтково.</target>
-<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ðе вдаєтьÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти %x до Корзини!</target>
+<source>Cannot access Volume Shadow Copy Service.</source>
+<target>Ðе вдаєтьÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ доÑтуп до поÑлуги тіньового ÐºÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ñ‚Ð¾Ð¼Ñƒ</target>
+
+<source>Please use FreeFileSync 64-bit version to create shadow copies on this system.</source>
+<target>Будь лаÑка, викориÑтовуйте 64-розрÑдну верÑÑ–ÑŽ FreeFileSync Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ñ–Ð½ÑŒÐ¾Ð²Ð¸Ñ… копій у цій ÑиÑтемі.</target>
<source>Cannot load file %x.</source>
<target>Ðе вдаєтьÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ файл %x.</target>
-<source>Error accessing Volume Shadow Copy Service!</source>
-<target>Помилка доÑтупу до поÑлуги Тіньового ÐšÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ Ð¢Ð¾Ð¼Ñƒ</target>
-
-<source>Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version.</source>
-<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ñ–Ð½ÑŒÐ¾Ð²Ð¸Ñ… копій на WOW64 не підтримуєтьÑÑ. Будь лаÑка, викориÑтайте FreeFileSync 64-розрÑдної верÑÑ–Ñ—.</target>
-
-<source>Cannot determine volume name for file:</source>
-<target>Ðе вдаєтьÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ назву тому Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð°:</target>
+<source>Path %x does not contain a volume name.</source>
+<target>ШлÑÑ… %x не міÑтить імені тому</target>
<source>Volume name %x not part of file name %y!</source>
<target>Ð†Ð¼â€™Ñ Ñ‚Ð¾Ð¼Ñƒ %x не Ñ” чаÑтиною імені файлу %y!</target>
-<source>/sec</source>
-<target>/Ñек</target>
-
-<source>File does not exist:</source>
-<target>Файл не Ñ–Ñнує:</target>
+<source>Cannot find file %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ файлу %x.</target>
<source>Cannot read the following XML elements:</source>
<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ такі елементи XML:</target>
@@ -300,15 +303,18 @@ The command line is executed each time:
<source>Start</source>
<target>Старт</target>
+<source>&Retry</source>
+<target>&Повторити</target>
+
+<source>Cancel</source>
+<target>Відмінити</target>
+
<source>(Build: %x)</source>
<target>(компілÑÑ†Ñ–Ñ %x)</target>
<source>RealtimeSync configuration</source>
<target>ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ RealtimeSync</target>
-<source>File already exists. Overwrite?</source>
-<target>Файл уже Ñ–Ñнує. ПерезапиÑати?</target>
-
<source>&Restore</source>
<target>&Відновити</target>
@@ -351,35 +357,38 @@ The command line is executed each time:
<source>FreeFileSync configuration</source>
<target>ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ FreeFileSync</target>
-<source>FreeFileSync Batch Job</source>
-<target>Пакетне Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ FreeFileSync</target>
-
-<source>Unable to create log file!</source>
-<target>Ðе можна Ñтворити лог-файл!</target>
-
<source>Batch execution</source>
<target>Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÐµÑ‚Ð½Ð¾Ð³Ð¾ завданнÑ</target>
-<source>Stop</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>Synchronization aborted!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð°!</target>
<source>Synchronization completed with errors!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ð»Ð°ÑÑ Ð· помилками!</target>
+<source>Nothing to synchronize!</source>
+<target>Ðічого Ñинхронізувати!</target>
+
<source>Synchronization completed successfully!</source>
<target>Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾Ð¹ÑˆÐ»Ð° уÑпішно!</target>
-<source>Press "Switch" to open FreeFileSync GUI mode.</source>
-<target>ÐатиÑніть "Змінити" Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð³Ñ€Ð°Ñ„Ñ–Ñ‡Ð½Ð¾Ð³Ð¾ інтерфейÑу FreeFileSync.</target>
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>ÐатиÑніть "Змінити" Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ð¿Ð¸Ñ‚Ð°Ð½ÑŒ у головному вікні FreeFileSync.</target>
-<source>Switching to FreeFileSync GUI mode...</source>
-<target>Перехід до графічного інтерфейÑу FreeFileSync...</target>
+<source>Switching to FreeFileSync main dialog...</source>
+<target>Перехід до головного діалогу FreeFileSync...</target>
<source>Unable to connect to sourceforge.net!</source>
<target>Ðе можна з’єднатиÑÑ Ð· sourceforge.net!</target>
@@ -540,9 +549,6 @@ The command line is executed each time:
<source>Items found:</source>
<target>Елементів знайдено:</target>
-<source>Items remaining:</source>
-<target>Елементів залишилоÑÑŒ:</target>
-
<source>Speed:</source>
<target>ШвидкіÑÑ‚ÑŒ:</target>
@@ -594,9 +600,6 @@ The command line is executed each time:
<source>&Load</source>
<target>&Завантажити</target>
-<source>&Cancel</source>
-<target>&Відмінити</target>
-
<source>Select variant:</source>
<target>Виберіть варіант:</target>
@@ -645,8 +648,8 @@ The command line is executed each time:
<source>Conflict/file cannot be categorized</source>
<target>Ðе можна категоризувати конфлікт/файл</target>
-<source>&OK</source>
-<target>&OK</target>
+<source>OK</source>
+<target>OK</target>
<source>Compare by...</source>
<target>Критерії порівнюваннÑ</target>
@@ -677,9 +680,6 @@ is the same
<source>Synchronizing...</source>
<target>СинхронізаціÑ...</target>
-<source>Items processed:</source>
-<target>Елементів оброблено:</target>
-
<source>&Pause</source>
<target>&Пауза</target>
@@ -719,9 +719,6 @@ is the same
<source>&Ignore</source>
<target>&Ігнорувати</target>
-<source>&Retry</source>
-<target>&Повторити</target>
-
<source>Do not show this dialog again</source>
<target>Ðадалі не показувати це вікно</target>
@@ -1019,9 +1016,6 @@ Exclude: \stuff\temp\*
<source>File list exported!</source>
<target>СпиÑок файлів екÑпортовано!</target>
-<source>Error writing file:</source>
-<target>Помилка при запиÑÑ– файлу:</target>
-
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
@@ -1071,21 +1065,21 @@ Exclude: \stuff\temp\*
<source>Paused</source>
<target>Призупинено</target>
+<source>Initializing...</source>
+<target>ІніціалізаціÑ...</target>
+
<source>Aborted</source>
<target>Перервано</target>
<source>Completed</source>
<target>Завершено</target>
-<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Запит перериваннÑ: Ð’ очікуванні Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— операції...</target>
+<source>Continue</source>
+<target>Далі</target>
<source>Pause</source>
<target>Пауза</target>
-<source>Continue</source>
-<target>Далі</target>
-
<source>Cannot find %x</source>
<target>Ðе можна знайти %x</target>
@@ -1229,65 +1223,65 @@ Exclude: \stuff\temp\*
<pluralform>%x днів</pluralform>
</target>
-<source>Could not initialize directory monitoring:</source>
-<target>Ðе вдалоÑÑ Ñ–Ð½Ñ–Ñ†Ñ–ÑŽÐ²Ð°Ñ‚Ð¸ каталог Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ:</target>
-
-<source>Error when monitoring directories.</source>
-<target>Помилка моніторингу каталогу.</target>
+<source>Cannot monitor directory %x.</source>
+<target>Ðе вдаєтьÑÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŽÐ²Ð°Ñ‚Ð¸ каталог %x.</target>
<source>Conversion error:</source>
<target>Помилка перетвореннÑ:</target>
-<source>Error deleting file:</source>
-<target>Помилка при вилученні файлу:</target>
+<source>Cannot delete file %x.</source>
+<target>Ðе вдаєтьÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ файл %Ñ….</target>
-<source>Error moving file:</source>
-<target>Помилка Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ:</target>
+<source>The file is locked by another process:</source>
+<target>Файл заблоковано іншим процеÑом:</target>
-<source>Target file already existing!</source>
-<target>Кінцевий файл уже Ñ–Ñнує!</target>
+<source>Cannot move file %x to %y.</source>
+<target>Ðе вдаєтьÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити файл %x до %y.</target>
-<source>Error moving directory:</source>
-<target>Помилка Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ñƒ:</target>
+<source>Cannot delete directory %x.</source>
+<target>Ðе вдаєтьÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ каталог Ñ…%.</target>
-<source>Target directory already existing!</source>
-<target>Кінцевий каталог вже Ñ–Ñнує!</target>
+<source>Cannot write modification time of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð°Ð¿Ð¸Ñати чаÑу модифікації %Ñ….</target>
-<source>Error deleting directory:</source>
-<target>Помилка при вилученні каталогу:</target>
+<source>Cannot find system function %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ ÑиÑтемної функції %x.</target>
-<source>Error changing modification time:</source>
-<target>Помилка при зміні чаÑу модификації файлу:</target>
+<source>Cannot read security context of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ контекÑту безпеки %Ñ….</target>
-<source>Error loading library function:</source>
-<target>Помилка при завантаженні функції бібліотеки:</target>
+<source>Cannot write security context of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð°Ð¿Ð¸Ñати контекÑту безпеки %Ñ….</target>
-<source>Error reading security context:</source>
-<target>Помилка при читанні контекÑту безпеки:</target>
+<source>Cannot read permissions of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ дозволів %Ñ….</target>
-<source>Error writing security context:</source>
-<target>Помилка при запиÑÑ– контекÑту безпеки:</target>
+<source>Cannot write permissions of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð°Ð¿Ð¸Ñати дозволів %Ñ….</target>
-<source>Error copying file permissions:</source>
-<target>Помилка при копіюванні прав доÑтупу:</target>
+<source>Cannot create directory %x.</source>
+<target>Ðе вдаєтьÑÑ Ñтворити каталогу %x.</target>
-<source>Error creating directory:</source>
-<target>Помилка при Ñтворенні каталогу:</target>
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>Ðе вдаєтьÑÑ Ð·ÐºÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ñ‚Ð¸ Ñимвольне поÑÐ¸Ð»Ð°Ð½Ð½Ñ %Ñ… в %y.</target>
-<source>Error copying symbolic link:</source>
-<target>Помилка при копіюванні Ñимвольного поÑиланнÑ:</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð°Ð¿Ð¸Ñати атрибути файла %x.</target>
-<source>Error copying file:</source>
-<target>Помилка при копіюванні файлу:</target>
+<source>Cannot copy file %x to %y.</source>
+<target>Ðе вдаєтьÑÑ Ð·ÐºÐ¾Ð¿Ñ–ÑŽÐ²Ð°Ñ‚Ð¸ файл %Ñ… до %y.</target>
-<source>Error traversing directory:</source>
-<target>Помилка обходу каталогу:</target>
+<source>Cannot read directory %x.</source>
+<target>Ðе вдаєтьÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ каталог %x</target>
-<source>Endless loop when traversing directory:</source>
-<target>Ð—Ð°Ñ†Ð¸ÐºÐ»ÑŽÐ²Ð°Ð½Ð½Ð½Ñ Ð¿Ñ€Ð¸ обході каталогу:</target>
+<source>Endless loop.</source>
+<target>ÐеÑкінченний цикл.</target>
-<source>Error setting privilege:</source>
-<target>Помилка вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð²Ð¸Ð»ÐµÑ—Ð²:</target>
+<source>Cannot set privilege %x.</source>
+<target>Ðе вдаєтьÑÑ Ð²Ñтановити привілеї %Ñ….</target>
+
+<source>Unable to move %x to the Recycle Bin!</source>
+<target>Ðе вдаєтьÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти %x до Корзини!</target>
<source>Both sides have changed since last synchronization!</source>
<target>З моменту оÑтанньої Ñинхронізації з обох Ñторін відбулиÑÑ Ð·Ð¼Ñ–Ð½Ð¸!</target>
@@ -1316,8 +1310,8 @@ Exclude: \stuff\temp\*
<source>You can ignore this error to consider the directory as empty.</source>
<target>Ви можете проігнорувати помилку, вважаючи каталог порожнім.</target>
-<source>Directory does not exist:</source>
-<target>Каталог не Ñ–Ñнує:</target>
+<source>Cannot find directory %x.</source>
+<target>Ðе вдаєтьÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ каталог Ñ…%.</target>
<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
<target>Залежні каталоги! Будьте уважні при налаштуванні правил Ñинхронізації:</target>
@@ -1325,20 +1319,17 @@ Exclude: \stuff\temp\*
<source>Preparing synchronization...</source>
<target>Підготовка до Ñинхронізації...</target>
-<source>Out of memory!</source>
-<target>Бракує пам'ÑÑ‚Ñ–!</target>
+<source>Conflict detected:</source>
+<target>ВиÑвлено конфлікт:</target>
<source>File %x has an invalid date!</source>
<target>Файл %x має неіÑнуючу дату!</target>
-<source>Conflict detected:</source>
-<target>ВиÑвлено конфлікт:</target>
-
<source>Files %x have the same date but a different size!</source>
<target>Файли %x мають однакову дату, але різні за розміром!</target>
-<source>Symlinks %x have the same date but a different target!</source>
-<target>Символьне поÑÐ¸Ð»Ð°Ð½Ð½Ð½Ñ %x має таку ж дату, але різний вміÑÑ‚!</target>
+<source>Symbolic links %x have the same date but a different target.</source>
+<target>Символьні поÑÐ¸Ð»Ð°Ð½Ð½Ñ %Ñ… мають таку ж дату, але різні цілі.</target>
<source>Comparing content of files %x</source>
<target>ÐŸÐ¾Ñ€Ñ–Ð²Ð½ÑŽÐ²Ð°Ð½Ð½Ñ Ð²Ð¼Ñ–Ñту файлів %x</target>
@@ -1421,12 +1412,12 @@ Exclude: \stuff\temp\*
<source>Creating file %x</source>
<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ %x</target>
-<source>Creating folder %x</source>
-<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸ %x</target>
-
<source>Creating symbolic link %x</source>
<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñимвольного поÑÐ¸Ð»Ð°Ð½Ð½Ñ %x</target>
+<source>Creating folder %x</source>
+<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°Ð¿ÐºÐ¸ %x</target>
+
<source>Overwriting file %x</source>
<target>ÐŸÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñ Ñ„Ð°Ð¹Ð»Ñƒ %x</target>
@@ -1445,8 +1436,8 @@ Exclude: \stuff\temp\*
<source>Directory for file versioning was not supplied!</source>
<target>Ðе вказаний каталог Ð´Ð»Ñ Ñтарих верÑій файлів!</target>
-<source>Source directory does not exist anymore:</source>
-<target>Каталог-джерело вже не Ñ–Ñнує:</target>
+<source>Source directory %x not found.</source>
+<target>Вихідний каталог %x не знайдено.</target>
<source>Unresolved conflicts existing!</source>
<target>Є невирішені конфлікти</target>
@@ -1481,12 +1472,6 @@ Exclude: \stuff\temp\*
<source>Generating database...</source>
<target>Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних...</target>
-<source>Nothing to synchronize!</source>
-<target>Ðічого Ñинхронізувати!</target>
-
-<source>Unable to copy locked file %x!</source>
-<target>Ðе можу зкопіювати заблокований файл %x!</target>
-
<source>Data verification error: Source and target file have different content!</source>
<target>Помилка перевірки даних: вхідний Ñ– вихідний файли мають різний вміÑÑ‚!</target>
diff --git a/BUILD/Resources.zip b/BUILD/Resources.zip
index 14244da2..2a5cfacd 100644
--- a/BUILD/Resources.zip
+++ b/BUILD/Resources.zip
Binary files differ
diff --git a/BUILD/styles.rc b/BUILD/styles.rc
index 0b7f0b20..c6b1b5ab 100644
--- a/BUILD/styles.rc
+++ b/BUILD/styles.rc
@@ -1,6 +1,8 @@
style "no-inner-border"
{
- GtkButton::inner-border = {0, 0, 0, 0}
+ GtkButton::focus-padding = 0
+ GtkButton::focus-line-width = 0
+ GtkButton::inner-border = {0, 0, 0, 0}
}
class "GtkButton" style "no-inner-border"
diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp
index c3b8f6f0..5fce963e 100644
--- a/FreeFileSync.cbp
+++ b/FreeFileSync.cbp
@@ -159,7 +159,6 @@
<Unit filename="lib\dir_exist_async.h" />
<Unit filename="lib\dir_lock.cpp" />
<Unit filename="lib\dir_lock.h" />
- <Unit filename="lib\error_log.h" />
<Unit filename="lib\ffs_paths.h" />
<Unit filename="lib\gtest\main.cpp">
<Option target="Unit Test" />
@@ -192,10 +191,16 @@
<Unit filename="lib\parallel_scan.h" />
<Unit filename="lib\parse_lng.h" />
<Unit filename="lib\parse_plural.h" />
+ <Unit filename="lib\perf_check.cpp">
+ <Option target="Release" />
+ <Option target="Debug-DLL" />
+ </Unit>
+ <Unit filename="lib\perf_check.h">
+ <Option target="Release" />
+ <Option target="Debug-DLL" />
+ </Unit>
<Unit filename="lib\process_xml.cpp" />
<Unit filename="lib\process_xml.h" />
- <Unit filename="lib\recycler.cpp" />
- <Unit filename="lib\recycler.h" />
<Unit filename="lib\resolve_path.cpp" />
<Unit filename="lib\resolve_path.h" />
<Unit filename="lib\resources.cpp" />
@@ -203,8 +208,6 @@
<Unit filename="lib\shadow.cpp" />
<Unit filename="lib\shadow.h" />
<Unit filename="lib\soft_filter.h" />
- <Unit filename="lib\statistics.cpp" />
- <Unit filename="lib\statistics.h" />
<Unit filename="lib\status_handler.cpp" />
<Unit filename="lib\status_handler.h" />
<Unit filename="lib\xml_base.cpp" />
@@ -484,12 +487,15 @@
<Unit filename="zen\privilege.cpp" />
<Unit filename="zen\privilege.h" />
<Unit filename="zen\read_txt.h" />
+ <Unit filename="zen\recycler.cpp" />
+ <Unit filename="zen\recycler.h" />
<Unit filename="zen\stl_tools.h" />
<Unit filename="zen\string_base.h" />
<Unit filename="zen\string_tools.h" />
<Unit filename="zen\string_traits.h" />
<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" />
diff --git a/FreeFileSync.vcxproj b/FreeFileSync.vcxproj
index f9b1c35d..5f3018cb 100644
--- a/FreeFileSync.vcxproj
+++ b/FreeFileSync.vcxproj
@@ -49,7 +49,7 @@
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v110</PlatformToolset>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -72,14 +72,14 @@
<OutDir>BUILD\Bin\</OutDir>
<IntDir>OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir>
<GenerateManifest>false</GenerateManifest>
- <TargetName>$(ProjectName)_Debug</TargetName>
+ <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>BUILD\Bin\</OutDir>
<IntDir>OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir>
<GenerateManifest>false</GenerateManifest>
- <TargetName>$(ProjectName)_Debug</TargetName>
+ <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@@ -101,17 +101,14 @@
<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>
- <PrecompiledHeaderFile>wx+\pch.h</PrecompiledHeaderFile>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
+ <PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile>
- <ForcedIncludeFiles>zen/warn_static.h;wx+\pch.h</ForcedIncludeFiles>
+ <ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
- <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<MinimalRebuild>false</MinimalRebuild>
- <ShowIncludes>
- </ShowIncludes>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -119,20 +116,11 @@
<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>
- <LinkStatus>
- </LinkStatus>
- <ShowProgress>
- </ShowProgress>
- <Profile>true</Profile>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);</PreprocessorDefinitions>
</ResourceCompile>
- <Manifest>
- <SuppressDependencyElement>
- </SuppressDependencyElement>
- </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@@ -140,13 +128,14 @@
<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\lib\vc_dll\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories>
- <PrecompiledHeaderFile>wx+\pch.h</PrecompiledHeaderFile>
+ <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>
+ <PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile>
- <ForcedIncludeFiles>zen/warn_static.h;wx+\pch.h</ForcedIncludeFiles>
+ <ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
@@ -157,16 +146,11 @@
<AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
<LinkStatus>
</LinkStatus>
- <Profile>true</Profile>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
</ResourceCompile>
- <Manifest>
- <SuppressDependencyElement>
- </SuppressDependencyElement>
- </Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@@ -175,12 +159,11 @@
<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++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
- <InlineFunctionExpansion>Default</InlineFunctionExpansion>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
</ClCompile>
<Link>
@@ -191,16 +174,10 @@
<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>
- <LinkStatus>
- </LinkStatus>
- <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
- <Profile>true</Profile>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);</PreprocessorDefinitions>
- <Culture>
- </Culture>
</ResourceCompile>
<PostBuildEvent>
<Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command>
@@ -213,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-VC11\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -227,22 +204,12 @@
<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-VC11\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
- <LinkStatus>
- </LinkStatus>
- <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
- <Profile>true</Profile>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
- <Culture>
- </Culture>
</ResourceCompile>
- <PreBuildEvent>
- <Command>
- </Command>
- </PreBuildEvent>
<PostBuildEvent>
<Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command>
</PostBuildEvent>
@@ -262,12 +229,11 @@
<ClCompile Include="lib\icon_buffer.cpp" />
<ClCompile Include="lib\localization.cpp" />
<ClCompile Include="lib\parallel_scan.cpp" />
+ <ClCompile Include="lib\perf_check.cpp" />
<ClCompile Include="lib\process_xml.cpp" />
- <ClCompile Include="lib\recycler.cpp" />
<ClCompile Include="lib\resolve_path.cpp" />
<ClCompile Include="lib\resources.cpp" />
<ClCompile Include="lib\shadow.cpp" />
- <ClCompile Include="lib\statistics.cpp" />
<ClCompile Include="lib\status_handler.cpp" />
<ClCompile Include="lib\xml_base.cpp" />
<ClCompile Include="structures.cpp" />
@@ -304,6 +270,7 @@
<ClCompile Include="zen\file_io.cpp" />
<ClCompile Include="zen\file_traverser.cpp" />
<ClCompile Include="zen\privilege.cpp" />
+ <ClCompile Include="zen\recycler.cpp" />
<ClCompile Include="zen\zstring.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/Makefile b/Makefile
index 0346b246..2d9859ee 100644
--- a/Makefile
+++ b/Makefile
@@ -71,12 +71,12 @@ CPP_LIST+=lib/icon_buffer.cpp
CPP_LIST+=lib/localization.cpp
CPP_LIST+=lib/parallel_scan.cpp
CPP_LIST+=lib/process_xml.cpp
-CPP_LIST+=lib/recycler.cpp
CPP_LIST+=lib/resolve_path.cpp
CPP_LIST+=lib/resources.cpp
-CPP_LIST+=lib/statistics.cpp
+CPP_LIST+=lib/perf_check.cpp
CPP_LIST+=lib/status_handler.cpp
CPP_LIST+=lib/xml_base.cpp
+CPP_LIST+=zen/recycler.cpp
CPP_LIST+=zen/file_handling.cpp
CPP_LIST+=zen/file_id.cpp
CPP_LIST+=zen/file_io.cpp
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp
index e1b46812..1a9469a8 100644
--- a/RealtimeSync/RealtimeSync.cbp
+++ b/RealtimeSync/RealtimeSync.cbp
@@ -81,7 +81,7 @@
<Add option="-DWXINTL_NO_GETTEXT_MACRO" />
<Add directory="C:\Programme\C++\wxWidgets\include" />
<Add directory="C:\Program Files\C++\Boost" />
- <Add directory="..\." />
+ <Add directory=".." />
</Compiler>
<ResourceCompiler>
<Add directory="C:\Programme\C++\wxWidgets\include" />
diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj
index f115bac4..8a062159 100644
--- a/RealtimeSync/RealtimeSync.vcxproj
+++ b/RealtimeSync/RealtimeSync.vcxproj
@@ -49,7 +49,7 @@
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v110</PlatformToolset>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -71,15 +71,15 @@
<LinkIncremental>true</LinkIncremental>
<OutDir>..\BUILD\Bin\</OutDir>
<IntDir>..\OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir>
- <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
<GenerateManifest>false</GenerateManifest>
+ <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\BUILD\Bin\</OutDir>
<IntDir>..\OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir>
- <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
<GenerateManifest>false</GenerateManifest>
+ <TargetName>$(ProjectName)_$(PlatformName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@@ -101,24 +101,21 @@
<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++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
- <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings>
- <MultiProcessorCompilation>false</MultiProcessorCompilation>
- <DisableLanguageExtensions>false</DisableLanguageExtensions>
+ <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
<PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile>
<ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <SuppressStartupBanner>true</SuppressStartupBanner>
<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>
- <LinkStatus>
- </LinkStatus>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -131,20 +128,19 @@
<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\lib\vc_dll\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories>
+ <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>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
- <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings>
- <MultiProcessorCompilation>false</MultiProcessorCompilation>
- <DisableLanguageExtensions>false</DisableLanguageExtensions>
+ <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
<PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile>
<ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SuppressStartupBanner>true</SuppressStartupBanner>
+ <MinimalRebuild>false</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <SuppressStartupBanner>true</SuppressStartupBanner>
<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>
@@ -162,14 +158,12 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
<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++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
- <DisableLanguageExtensions>false</DisableLanguageExtensions>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
</ClCompile>
<Link>
@@ -177,19 +171,13 @@
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <SuppressStartupBanner>true</SuppressStartupBanner>
<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>
- <LinkStatus>
- </LinkStatus>
- <Profile>true</Profile>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);</PreprocessorDefinitions>
- <Culture>
- </Culture>
</ResourceCompile>
<PostBuildEvent>
<Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command>
@@ -201,15 +189,12 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
<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-VC11\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
- <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings>
+ <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
- <DisableLanguageExtensions>false</DisableLanguageExtensions>
- <SuppressStartupBanner>true</SuppressStartupBanner>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
</ClCompile>
<Link>
@@ -217,19 +202,13 @@
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
- <SuppressStartupBanner>true</SuppressStartupBanner>
<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-VC11\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
- <LinkStatus>
- </LinkStatus>
- <Profile>true</Profile>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
- <Culture>
- </Culture>
</ResourceCompile>
<PostBuildEvent>
<Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command>
@@ -257,7 +236,6 @@
<ClCompile Include="application.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">wx+/pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="gui_generated.cpp" />
<ClCompile Include="main_dlg.cpp" />
@@ -271,8 +249,9 @@
<ResourceCompile Include="resource.rc" />
</ItemGroup>
<ItemGroup>
- <None Include="ClassDiagram.cd" />
- <None Include="WxWizDialog.fbp" />
+ <None Include="WxWizFrame.fbp">
+ <SubType>Designer</SubType>
+ </None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp
index ead65eaa..4c477ce0 100644
--- a/RealtimeSync/application.cpp
+++ b/RealtimeSync/application.cpp
@@ -67,12 +67,12 @@ void Application::OnStartApplication(wxIdleEvent& event)
if (!fileExists(filename)) //be a little tolerant
{
if (fileExists(filename + Zstr(".ffs_real")))
- filename = filename + Zstr(".ffs_real");
+ filename += Zstr(".ffs_real");
else if (fileExists(filename + Zstr(".ffs_batch")))
- filename = filename + Zstr(".ffs_batch");
+ filename += Zstr(".ffs_batch");
else
{
- wxMessageBox(wxString(_("File does not exist:")) + wxT(" \"") + toWx(filename) + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)), _("Error"), wxOK | wxICON_ERROR);
return;
}
}
@@ -103,11 +103,21 @@ int Application::OnRun()
}
catch (const std::exception& e) //catch all STL exceptions
{
- //unfortunately it's not always possible to display a message box in this erroneous situation, however (non-stream) file output always works!
- wxFile safeOutput(toWx(zen::getConfigDir()) + wxT("LastError.txt"), wxFile::write);
- safeOutput.Write(wxString::FromAscii(e.what()));
+ //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(utf8CvrtTo<wxString>(e.what()));
- wxSafeShowMessage(_("An exception occurred!") + L" - RTS", wxString::FromAscii(e.what()));
+ wxSafeShowMessage(_("An exception occurred!") + L" - RTS", utf8CvrtTo<wxString>(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);
return -9;
}
diff --git a/RealtimeSync/gui_generated.cpp b/RealtimeSync/gui_generated.cpp
index 849915a4..9bcbda52 100644
--- a/RealtimeSync/gui_generated.cpp
+++ b/RealtimeSync/gui_generated.cpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Feb 9 2012)
+// C++ code generated with wxFormBuilder (version Apr 10 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@@ -164,7 +164,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
bSizer1->Add( sbSizer4, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
- m_buttonStart = new zen::BitmapButton( m_panelMain, wxID_ANY, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 );
+ m_buttonStart = new zen::BitmapButton( m_panelMain, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 );
m_buttonStart->SetDefault();
m_buttonStart->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) );
@@ -246,3 +246,65 @@ FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint
FolderGenerated::~FolderGenerated()
{
}
+
+ErrorDlgGenerated::ErrorDlgGenerated( 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 );
+
+ 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( 48,48 ), 0 );
+ bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY );
+ m_textCtrl8->SetBackgroundColour( wxColour( 224, 224, 224 ) );
+
+ bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 );
+
+
+ bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
+
+ wxBoxSizer* bSizer25;
+ bSizer25 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_buttonRetry = new wxButton( this, wxID_RETRY, _("&Retry"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonRetry->SetDefault();
+ m_buttonRetry->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+
+ bSizer25->Add( m_buttonRetry, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_buttonAbort = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+
+ bSizer25->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
+
+
+ bSizer24->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
+
+
+ this->SetSizer( bSizer24 );
+ this->Layout();
+
+ this->Centre( wxBOTH );
+
+ // Connect Events
+ this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ErrorDlgGenerated::OnClose ) );
+ 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_buttonRetry->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this );
+ m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this );
+
+}
diff --git a/RealtimeSync/gui_generated.h b/RealtimeSync/gui_generated.h
index aa0f5ad8..1989653f 100644
--- a/RealtimeSync/gui_generated.h
+++ b/RealtimeSync/gui_generated.h
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Feb 9 2012)
+// C++ code generated with wxFormBuilder (version Apr 10 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@@ -34,6 +34,8 @@
#include <wx/scrolwin.h>
#include <wx/spinctrl.h>
#include <wx/frame.h>
+#include <wx/statbmp.h>
+#include <wx/dialog.h>
#include "../zen/i18n.h"
@@ -111,4 +113,30 @@ public:
};
+///////////////////////////////////////////////////////////////////////////////
+/// Class ErrorDlgGenerated
+///////////////////////////////////////////////////////////////////////////////
+class ErrorDlgGenerated : public wxDialog
+{
+private:
+
+protected:
+ wxStaticBitmap* m_bitmap10;
+ wxTextCtrl* m_textCtrl8;
+ wxButton* m_buttonRetry;
+ wxButton* m_buttonAbort;
+
+ // Virtual event handlers, overide them in your derived class
+ virtual void OnClose( wxCloseEvent& 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( 460,250 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
+ ~ErrorDlgGenerated();
+
+};
+
#endif //__GUI_GENERATED_H__
diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp
index c91e4856..dfb1a85e 100644
--- a/RealtimeSync/main_dlg.cpp
+++ b/RealtimeSync/main_dlg.cpp
@@ -59,15 +59,15 @@ MainDialog::MainDialog(wxDialog* dlg, const wxString& cfgFileName)
if (!cfgFileName.empty() || wxFileExists(lastConfigFileName()))
try
{
- rts::readRealOrBatchConfig(currentConfigFile, newConfig);
+ rts::readRealOrBatchConfig(toZ(currentConfigFile), newConfig);
loadCfgSuccess = true;
}
catch (const xmlAccess::FfsXmlError& error)
{
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING);
+ wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
else
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
}
const bool startWatchingImmediately = loadCfgSuccess && !cfgFileName.empty();
@@ -102,30 +102,18 @@ MainDialog::~MainDialog()
try //write config to XML
{
- writeRealConfig(currentCfg, lastConfigFileName());
+ writeRealConfig(currentCfg, toZ(lastConfigFileName()));
}
catch (const xmlAccess::FfsXmlError& error)
{
- wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
}
}
-void MainDialog::OnClose(wxCloseEvent& event)
-{
- Destroy();
-}
-
-
-void MainDialog::OnQuit(wxCommandEvent& event)
-{
- Destroy();
-}
-
-
const wxString& MainDialog::lastConfigFileName()
{
- static wxString instance = toWx(zen::getConfigDir()) + wxT("LastRun.ffs_real");
+ static wxString instance = toWx(zen::getConfigDir()) + L"LastRun.ffs_real";
return instance;
}
@@ -145,23 +133,19 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event)
//build information
wxString build = __TDATE__;
#if wxUSE_UNICODE
- build += wxT(" - Unicode");
+ build += L" - Unicode";
#else
- build += wxT(" - ANSI");
+ build += L" - ANSI";
#endif //wxUSE_UNICODE
//compile time info about 32/64-bit build
if (zen::is64BitBuild)
- build += wxT(" x64");
+ build += L" x64";
else
- build += wxT(" x86");
+ build += L" x86";
assert_static(zen::is32BitBuild || zen::is64BitBuild);
- wxString buildFormatted = _("(Build: %x)");
- buildFormatted.Replace(wxT("%x"), build);
-
- wxMessageDialog* aboutDlg = new wxMessageDialog(this, wxString(L"RealtimeSync") + L"\n\n" + buildFormatted, _("About"), wxOK);
- aboutDlg->ShowModal();
+ wxMessageBox(L"RealtimeSync" L"\n\n" + replaceCpy(_("(Build: %x)"), L"%x", build), _("About"), wxOK, this);
}
@@ -170,7 +154,7 @@ void MainDialog::OnKeyPressed(wxKeyEvent& event)
const int keyCode = event.GetKeyCode();
if (keyCode == WXK_ESCAPE)
- Destroy();
+ Close();
event.Skip();
}
@@ -184,52 +168,43 @@ void MainDialog::OnStart(wxCommandEvent& event)
switch (rts::startDirectoryMonitor(currentCfg, xmlAccess::extractJobName(currentConfigFileName)))
{
- case rts::QUIT:
- {
- Destroy();
+ case rts::EXIT_APP:
+ Close();
return;
- }
- break;
- case rts::RESUME:
+ case rts::SHOW_GUI:
break;
}
-
- Show();
+ Show(); //don't show for EXIT_APP
}
void MainDialog::OnSaveConfig(wxCommandEvent& event)
{
- wxString defaultFileName = currentConfigFileName.empty() ? wxT("Realtime.ffs_real") : currentConfigFileName;
+ 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!
- if (defaultFileName.EndsWith(wxT(".ffs_batch")))
- defaultFileName.Replace(wxT(".ffs_batch"), wxT(".ffs_real"), false);
+ if (endsWith(defaultFileName, L".ffs_batch"))
+ replace(defaultFileName, L".ffs_batch", L".ffs_real", false);
- wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("RealtimeSync configuration")) + wxT(" (*.ffs_real)|*.ffs_real"), wxFD_SAVE);
- if (filePicker->ShowModal() == wxID_OK)
- {
- const wxString newFileName = filePicker->GetPath();
+ wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, defaultFileName,
+ _("RealtimeSync configuration") + L" (*.ffs_real)|*.ffs_real",
+ wxFD_SAVE /*| wxFD_OVERWRITE_PROMPT*/);
+ if (filePicker.ShowModal() != wxID_OK)
+ return;
- if (wxFileExists(newFileName))
- {
- wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL);
- if (messageDlg->ShowModal() != wxID_OK)
- return OnSaveConfig(event); //retry
- }
+ const wxString newFileName = filePicker.GetPath();
- //write config to XML
- const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
- try
- {
- writeRealConfig(currentCfg, newFileName);
- setLastUsedConfig(newFileName);
- }
- catch (const zen::FileError& error)
- {
- wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR);
- }
+ //write config to XML
+ const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
+ try
+ {
+ writeRealConfig(currentCfg, toZ(newFileName)); //throw FfsXmlError
+ setLastUsedConfig(newFileName);
+ }
+ catch (const xmlAccess::FfsXmlError& e)
+ {
+ wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
}
}
@@ -240,7 +215,7 @@ void MainDialog::loadConfig(const wxString& filename)
try
{
- rts::readRealOrBatchConfig(filename, newConfig);
+ rts::readRealOrBatchConfig(toZ(filename), newConfig);
}
catch (const xmlAccess::FfsXmlError& error)
{
@@ -276,11 +251,11 @@ void MainDialog::setLastUsedConfig(const wxString& filename)
void MainDialog::OnLoadConfig(wxCommandEvent& event)
{
- wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, wxEmptyString,
- wxString(_("RealtimeSync configuration")) + wxT(" (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch"),
- wxFD_OPEN);
- if (filePicker->ShowModal() == wxID_OK)
- loadConfig(filePicker->GetPath());
+ wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, wxEmptyString,
+ _("RealtimeSync configuration") + L" (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch",
+ wxFD_OPEN);
+ if (filePicker.ShowModal() == wxID_OK)
+ loadConfig(filePicker.GetPath());
}
@@ -342,13 +317,11 @@ void MainDialog::OnRemoveFolder(wxCommandEvent& event)
//find folder pair originating the event
const wxObject* const eventObj = event.GetEventObject();
for (std::vector<DirectoryPanel*>::const_iterator i = dirNamesExtra.begin(); i != dirNamesExtra.end(); ++i)
- {
if (eventObj == static_cast<wxObject*>((*i)->m_bpButtonRemoveFolder))
{
removeAddFolder(i - dirNamesExtra.begin());
return;
}
- }
}
diff --git a/RealtimeSync/main_dlg.h b/RealtimeSync/main_dlg.h
index 01789a45..edc66c47 100644
--- a/RealtimeSync/main_dlg.h
+++ b/RealtimeSync/main_dlg.h
@@ -44,17 +44,17 @@ public:
void loadConfig(const wxString& filename);
private:
- virtual void OnClose( wxCloseEvent& event);
- virtual void OnQuit( wxCommandEvent& event);
- virtual void OnShowHelp( wxCommandEvent& event);
- virtual void OnMenuAbout( wxCommandEvent& event);
- virtual void OnAddFolder( wxCommandEvent& event);
- virtual void OnRemoveFolder( wxCommandEvent& event);
- 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 OnClose (wxCloseEvent& event) { Destroy(); }
+ virtual void OnQuit (wxCommandEvent& event) { Destroy(); }
+ virtual void OnShowHelp (wxCommandEvent& event);
+ virtual void OnMenuAbout (wxCommandEvent& event);
+ virtual void OnAddFolder (wxCommandEvent& event);
+ virtual void OnRemoveFolder (wxCommandEvent& event);
+ 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);
void setConfiguration(const xmlAccess::XmlRealConfig& cfg);
xmlAccess::XmlRealConfig getConfiguration();
diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp
index f81af50a..486aa8f1 100644
--- a/RealtimeSync/resources.cpp
+++ b/RealtimeSync/resources.cpp
@@ -23,7 +23,7 @@ const GlobalResources& GlobalResources::instance()
GlobalResources::GlobalResources()
{
- wxFFileInputStream input(toWx(zen::getResourceDir()) + wxT("Resources.zip"));
+ wxFFileInputStream input(toWx(zen::getResourceDir()) + L"Resources.zip");
if (input.IsOk()) //if not... we don't want to react too harsh here
{
//activate support for .png files
@@ -41,17 +41,17 @@ GlobalResources::GlobalResources()
const wxString name = entry->GetName();
//generic image loading
- if (name.EndsWith(wxT(".png")))
+ if (endsWith(name, L".png"))
bitmaps.insert(std::make_pair(name, wxImage(resourceFile, wxBITMAP_TYPE_PNG)));
}
}
#ifdef FFS_WIN
//for compatibility it seems we need to stick with a "real" icon
- programIcon = wxIcon(wxT("A_PROGRAM_ICON"));
+ programIcon = wxIcon(L"A_PROGRAM_ICON");
#else
//use big logo bitmap for better quality
- programIcon.CopyFromBitmap(getImageInt(wxT("RealtimeSync.png")));
+ programIcon.CopyFromBitmap(getImageInt(L"RealtimeSync.png"));
#endif
}
@@ -59,8 +59,8 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& name) const
{
- auto iter = bitmaps.find(name.Find(L'.') == wxNOT_FOUND ? //assume .png ending if nothing else specified
- name + wxT(".png") :
+ auto iter = bitmaps.find(!contains(name, L'.') ? //assume .png ending if nothing else specified
+ name + L".png" :
name);
if (iter != bitmaps.end())
return iter->second;
diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp
index e18101e0..4afef5e4 100644
--- a/RealtimeSync/tray_menu.cpp
+++ b/RealtimeSync/tray_menu.cpp
@@ -16,38 +16,42 @@
#include <wx/menu.h>
#include "watcher.h"
#include <wx/utils.h>
-#include <wx/log.h>
#include <wx/icon.h> //Linux needs this
#include <wx/timer.h>
+#include <wx+/mouse_move_dlg.h>
#include "resources.h"
#include <wx+/string_conv.h>
#include <zen/assert_static.h>
#include <zen/build_info.h>
#include <wx+/shell_execute.h>
+#include "gui_generated.h"
using namespace rts;
using namespace zen;
-class TrayIconHolder : private wxEvtHandler
+
+namespace
{
-public:
- TrayIconHolder(const wxString& jobname);
- ~TrayIconHolder();
+struct AbortCallback //never throw exceptions through a C-Layer (GUI)!
+{
+ virtual ~AbortCallback() {}
+ virtual void requestResume() = 0;
+ virtual void requestAbort() = 0;
+};
- void doUiRefreshNow();
- void showIconActive();
- void showIconWaiting();
- void requestAbort()
+//RtsTrayIcon is a dumb class whose sole purpose is to enable wxWidgets deferred deletion
+class RtsTrayIconRaw : public wxTaskBarIcon
+{
+public:
+ RtsTrayIconRaw(AbortCallback& abortCb) : abortCb_(&abortCb)
{
- m_abortRequested = true;
+ Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIconRaw::OnDoubleClick), nullptr, this);
}
- void OnRequestResume(wxCommandEvent& event)
- {
- m_resumeRequested = true;
- }
+ void dontCallBackAnymore() { abortCb_ = nullptr; } //call before tray icon is marked for deferred deletion
+private:
enum Selection
{
CONTEXT_ABORT,
@@ -55,34 +59,9 @@ public:
CONTEXT_ABOUT
};
- void OnContextMenuSelection(wxCommandEvent& event);
-
-private:
- class RtsTrayIcon;
- RtsTrayIcon* trayMenu;
-
- bool m_abortRequested;
- bool m_resumeRequested;
-
- const wxString jobName_; //RTS job name, may be empty
-};
-
-
-//RtsTrayIcon shall be a dumb class whose sole purpose is to enable wxWidgets deferred deletion
-class TrayIconHolder::RtsTrayIcon : public wxTaskBarIcon
-{
-public:
- RtsTrayIcon(TrayIconHolder* parent) : parent_(parent) {}
-
- void parentHasDied() //call before tray icon is marked for deferred deletion
- {
- parent_ = nullptr;
- }
-
-private:
virtual wxMenu* CreatePopupMenu()
{
- if (!parent_)
+ if (!abortCb_)
return nullptr;
wxMenu* contextMenu = new wxMenu;
@@ -91,169 +70,150 @@ private:
contextMenu->AppendSeparator();
contextMenu->Append(CONTEXT_ABORT, _("&Exit"));
//event handling
- contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TrayIconHolder::OnContextMenuSelection), nullptr, parent_);
+ contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RtsTrayIconRaw::OnContextMenuSelection), nullptr, this);
return contextMenu; //ownership transferred to caller
}
- TrayIconHolder* parent_;
-};
-//##############################################################################################################
+ void OnContextMenuSelection(wxCommandEvent& event)
+ {
+ if (!abortCb_)
+ return;
+ switch (static_cast<Selection>(event.GetId()))
+ {
+ case CONTEXT_ABORT:
+ abortCb_->requestAbort();
+ break;
-class AbortThisProcess //exception class
-{
-public:
- AbortThisProcess(MonitorResponse command) : command_(command) {}
+ case CONTEXT_RESTORE:
+ abortCb_->requestResume();
+ break;
+
+ case CONTEXT_ABOUT:
+ {
+ //build information
+ wxString build = __TDATE__;
+#if wxUSE_UNICODE
+ build += L" - Unicode";
+#else
+ build += L" - ANSI";
+#endif //wxUSE_UNICODE
+
+ //compile time info about 32/64-bit build
+ if (zen::is64BitBuild)
+ build += L" x64";
+ else
+ build += L" x86";
+ assert_static(zen::is32BitBuild || zen::is64BitBuild);
+
+ wxMessageBox(L"RealtimeSync" L"\n\n" + replaceCpy(_("(Build: %x)"), L"%x", build), _("About"), wxOK);
+ }
+ break;
+ }
+ }
- MonitorResponse getCommand() const
+ void OnDoubleClick(wxCommandEvent& event)
{
- return command_;
+ if (abortCb_)
+ abortCb_->requestResume();
}
-private:
- MonitorResponse command_;
+ AbortCallback* abortCb_;
};
-//##############################################################################################################
-TrayIconHolder::TrayIconHolder(const wxString& jobname) :
- m_abortRequested(false),
- m_resumeRequested(false),
- jobName_(jobname)
+class TrayIconHolder
{
- trayMenu = new RtsTrayIcon(this); //not in initialization list: give it a valid parent object!
-
- showIconActive();
-
- //register double-click
- trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), nullptr, this);
-}
-
+public:
+ TrayIconHolder(const wxString& jobname, AbortCallback& abortCb) :
+ jobName_(jobname)
+ {
+ trayMenu = new RtsTrayIconRaw(abortCb); //not in initialization list: give it a valid parent object!
+ showIconActive();
+ }
-TrayIconHolder::~TrayIconHolder()
-{
- trayMenu->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), nullptr, this);
- trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place
- trayMenu->parentHasDied();
+ ~TrayIconHolder()
+ {
+ trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place
+ trayMenu->dontCallBackAnymore();
- //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
- if (!wxPendingDelete.Member(trayMenu))
- wxPendingDelete.Append(trayMenu);
-}
+ //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
+ if (!wxPendingDelete.Member(trayMenu))
+ wxPendingDelete.Append(trayMenu);
+ }
+ void doUiRefreshNow()
+ {
+ wxTheApp->Yield();
+ } //yield is UI-layer which is represented by this tray icon
-void TrayIconHolder::showIconActive()
-{
- wxIcon realtimeIcon;
+ void showIconActive()
+ {
+ wxIcon realtimeIcon;
#ifdef FFS_WIN
- realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_win.png"))); //use a 16x16 bitmap
+ realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_win.png")); //use a 16x16 bitmap
#elif defined FFS_LINUX
- realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit
+ realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_linux.png")); //use a 22x22 bitmap for perfect fit
#endif
- const wxString postFix = jobName_.empty() ? wxString() : (wxT("\n\"") + jobName_ + wxT("\""));
- trayMenu->SetIcon(realtimeIcon, _("Monitoring active...") + postFix);
-}
-
+ const wxString postFix = jobName_.empty() ? wxString() : (L"\n\"" + jobName_ + L"\"");
+ trayMenu->SetIcon(realtimeIcon, _("Monitoring active...") + postFix);
+ }
-void TrayIconHolder::showIconWaiting()
-{
- wxIcon realtimeIcon;
+ void showIconWaiting()
+ {
+ wxIcon realtimeIcon;
#ifdef FFS_WIN
- realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_waiting_win.png"))); //use a 16x16 bitmap
+ realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_waiting_win.png")); //use a 16x16 bitmap
#elif defined FFS_LINUX
- realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_waiting_linux.png"))); //use a 22x22 bitmap for perfect fit
+ realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_waiting_linux.png")); //use a 22x22 bitmap for perfect fit
#endif
- const wxString postFix = jobName_.empty() ? wxString() : (wxT("\n\"") + jobName_ + wxT("\""));
- trayMenu->SetIcon(realtimeIcon, _("Waiting for missing directories...") + postFix);
-}
-
-
-void TrayIconHolder::OnContextMenuSelection(wxCommandEvent& event)
-{
- const int eventId = event.GetId();
- switch (static_cast<Selection>(eventId))
- {
- case CONTEXT_ABORT:
- requestAbort();
- break;
- case CONTEXT_RESTORE:
- OnRequestResume(event); //just remember: never throw exceptions through a C-Layer (GUI) ;)
- break;
- case CONTEXT_ABOUT:
- {
- //build information
- wxString build = __TDATE__;
-#if wxUSE_UNICODE
- build += wxT(" - Unicode");
-#else
- build += wxT(" - ANSI");
-#endif //wxUSE_UNICODE
-
- //compile time info about 32/64-bit build
- if (zen::is64BitBuild)
- build += wxT(" x64");
- else
- build += wxT(" x86");
- assert_static(zen::is32BitBuild || zen::is64BitBuild);
-
- wxString buildFormatted = _("(Build: %x)");
- buildFormatted.Replace(wxT("%x"), build);
-
- wxMessageDialog aboutDlg(nullptr, wxString(wxT("RealtimeSync")) + wxT("\n\n") + buildFormatted, _("About"), wxOK);
- aboutDlg.ShowModal();
- }
- break;
+ const wxString postFix = jobName_.empty() ? wxString() : (L"\n\"" + jobName_ + L"\"");
+ trayMenu->SetIcon(realtimeIcon, _("Waiting for missing directories...") + postFix);
}
-}
-
-void TrayIconHolder::doUiRefreshNow()
-{
- wxTheApp->Yield();
+private:
+ RtsTrayIconRaw* trayMenu;
+ const wxString jobName_; //RTS job name, may be empty
+};
- if (m_abortRequested)
- throw ::AbortThisProcess(QUIT);
- if (m_resumeRequested)
- throw ::AbortThisProcess(RESUME);
-}
//##############################################################################################################
-namespace
-{
-std::vector<Zstring> convert(const std::vector<wxString>& dirList)
+struct AbortMonitoring//exception class
{
- std::set<Zstring, LessFilename> output;
- std::transform(dirList.begin(), dirList.end(),
- std::inserter(output, output.end()), [](const wxString & str) { return zen::toZ(str); });
- return std::vector<Zstring>(output.begin(), output.end());
-}
-}
-
+ AbortMonitoring(AbortReason reasonCode) : reasonCode_(reasonCode) {}
+ AbortReason reasonCode_;
+};
class StartSyncNowException {};
+//##############################################################################################################
-class WaitCallbackImpl : public rts::WaitCallback
+class WaitCallbackImpl : public rts::WaitCallback, private AbortCallback
{
public:
WaitCallbackImpl(const wxString& jobname) :
- trayIcon(jobname),
- nextSyncStart_(std::numeric_limits<long>::max()) {}
+ trayIcon(jobname, *this),
+ nextSyncStart_(std::numeric_limits<long>::max()),
+ resumeRequested(false),
+ abortRequested(false) {}
- void notifyAllDirectoriesExist()
- {
- trayIcon.showIconActive();
- }
+ void notifyAllDirectoriesExist() { trayIcon.showIconActive(); }
+ void notifyDirectoryMissing () { trayIcon.showIconWaiting(); }
- void notifyDirectoryMissing()
- {
- trayIcon.showIconWaiting();
- }
+ void scheduleNextSync(long nextSyncStart) { nextSyncStart_ = nextSyncStart; }
+ void clearSchedule() { nextSyncStart_ = std::numeric_limits<long>::max(); }
- virtual void requestUiRefresh() //throw StartSyncNowException()
+ //implement WaitCallback
+ virtual void requestUiRefresh() //throw StartSyncNowException, AbortMonitoring
{
+ if (resumeRequested)
+ throw AbortMonitoring(SHOW_GUI);
+
+ if (abortRequested)
+ throw AbortMonitoring(EXIT_APP);
+
if (nextSyncStart_ <= wxGetLocalTime())
throw StartSyncNowException(); //abort wait and start sync
@@ -261,16 +221,87 @@ public:
trayIcon.doUiRefreshNow();
}
- void scheduleNextSync(long nextSyncStart)
+private:
+ //implement AbortCallback: used from C-GUI call stack
+ virtual void requestResume() { resumeRequested = true; }
+ virtual void requestAbort () { abortRequested = true; }
+
+ TrayIconHolder trayIcon;
+ long nextSyncStart_;
+ bool resumeRequested;
+ bool abortRequested;
+};
+
+
+
+class ErrorDlgWithTimeout : public ErrorDlgGenerated
+{
+public:
+ ErrorDlgWithTimeout(wxWindow* parent, const wxString& messageText) :
+ ErrorDlgGenerated(parent),
+ secondsLeft(15) //give user some time to read msg!?
{
- nextSyncStart_ = nextSyncStart;
+#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);
+ m_buttonRetry->SetFocus();
+
+ //count down X seconds then automatically press "retry"
+ timer.Connect(wxEVT_TIMER, wxEventHandler(ErrorDlgWithTimeout::OnTimerEvent), nullptr, this);
+ timer.Start(1000); //timer interval in ms
+ updateButtonLabel();
}
+ enum ButtonPressed
+ {
+ BUTTON_RETRY,
+ BUTTON_ABORT
+ };
+
private:
- TrayIconHolder trayIcon;
- long nextSyncStart_;
+ void OnTimerEvent(wxEvent& event)
+ {
+ --secondsLeft;
+ if (secondsLeft < 0)
+ {
+ EndModal(BUTTON_RETRY);
+ return;
+ }
+ updateButtonLabel();
+ }
+
+ void updateButtonLabel()
+ {
+ m_buttonRetry->SetLabel(_("&Retry") + L" (" + replaceCpy(_P("1 sec", "%x sec", secondsLeft), L"%x", numberTo<std::wstring>(secondsLeft)) + L")");
+ Layout();
+ }
+
+ void OnClose(wxCloseEvent& event) { EndModal(BUTTON_ABORT); }
+ void OnRetry(wxCommandEvent& event) { EndModal(BUTTON_RETRY); }
+ void OnAbort(wxCommandEvent& event) { EndModal(BUTTON_ABORT); }
+
+ int secondsLeft;
+ wxTimer timer;
};
+
+bool reportErrorTimeout(const std::wstring& msg) //return true if timeout or user selected "retry", else abort
+{
+ ErrorDlgWithTimeout errorDlg(nullptr, msg);
+ //errorDlg.Raise(); -> don't steal focus every X seconds
+ switch (static_cast<ErrorDlgWithTimeout::ButtonPressed>(errorDlg.ShowModal()))
+ {
+ case ErrorDlgWithTimeout::BUTTON_RETRY:
+ return true;
+ case ErrorDlgWithTimeout::BUTTON_ABORT:
+ return false;
+ }
+ return false;
+}
+}
+
/*
Data Flow:
----------
@@ -278,82 +309,96 @@ Data Flow:
TrayIconHolder (GUI output)
/|\
|
-WaitCallbackImpl (higher level "interface")
+WaitCallbackImpl
/|\
|
startDirectoryMonitor() (wire dir-changes and execution of commandline)
- /|\
- |
-watcher.h (low level wait for directory changes)
*/
-rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname)
+rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname)
{
- Zstring lastFileChanged;
+ const std::vector<Zstring> dirList = toZ(config.directories);
+
+ auto cmdLine = config.commandline;
+ trim(cmdLine);
+
+ if (cmdLine.empty())
+ {
+ wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\"\""), _("Error"), wxOK | wxICON_ERROR);
+ return SHOW_GUI;
+ }
+ if (dirList.empty() || std::any_of(dirList.begin(), dirList.end(), [](Zstring str) -> bool { trim(str); return str.empty(); }))
+ {
+ wxMessageBox(_("A directory input field is empty."), _("Error"), wxOK | wxICON_ERROR);
+ return SHOW_GUI;
+ }
- const std::vector<Zstring> dirList = convert(config.directories);
try
{
+ Zstring lastFileChanged;
WaitCallbackImpl callback(jobname);
- if (config.commandline.empty())
- {
- std::wstring errorMsg = _("Invalid command line: %x");
- replace(errorMsg, L"%x", L"\"" + config.commandline + L"\"");
- throw FileError(errorMsg);
- }
-
- callback.notifyDirectoryMissing();
- waitForMissingDirs(dirList, &callback);
- callback.notifyAllDirectoriesExist();
-
- while (true)
+ auto execMonitoring = [&] //throw FileError, AbortMonitoring
{
- ::wxSetEnv(L"changed_file", utf8CvrtTo<wxString>(lastFileChanged)); //some way to output what file changed to the user
- lastFileChanged.clear(); //make sure old name is not shown again after a directory reappears
-
- //execute command
- zen::shellExecute(config.commandline, zen::EXEC_TYPE_SYNC);
+ callback.clearSchedule();
- wxLog::FlushActive(); //show wxWidgets error messages (if any)
+ callback.notifyDirectoryMissing();
+ waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring
+ callback.notifyAllDirectoriesExist();
- callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet)
+ //schedule initial execution only AFTER waitForMissingDirs(), else StartSyncNowException might be thrown while directory checking hangs
+ callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay));
- try
+ while (true)
{
- while (true)
+ try
{
- //wait for changes (and for all directories to become available)
- WaitResult res = waitForChanges(dirList, &callback);
- switch (res.type)
+ while (true)
{
- case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available!
- callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet)
- callback.notifyDirectoryMissing();
- waitForMissingDirs(dirList, &callback);
- callback.notifyAllDirectoriesExist();
- break;
- case CHANGE_DETECTED:
- lastFileChanged = res.filename;
- break;
+ //wait for changes (and for all directories to become available)
+ WaitResult res = waitForChanges(dirList, callback); //throw FileError, StartSyncNowException, AbortMonitoring
+ switch (res.type)
+ {
+ case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available!
+ callback.clearSchedule();
+
+ callback.notifyDirectoryMissing();
+ waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring
+ callback.notifyAllDirectoriesExist();
+ break;
+
+ case CHANGE_DETECTED:
+ lastFileChanged = res.filename;
+ break;
+ }
+ callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay));
}
-
- callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay));
}
+ catch (StartSyncNowException&) {}
+
+ ::wxSetEnv(L"changed_file", utf8CvrtTo<wxString>(lastFileChanged)); //some way to output what file changed to the user
+ lastFileChanged.clear(); //make sure old name is not shown again after a directory reappears
+
+ //execute command
+ zen::shellExecute(cmdLine, zen::EXEC_TYPE_SYNC);
+ callback.clearSchedule();
+ }
+ };
+
+ while (true)
+ try
+ {
+ execMonitoring(); //throw FileError, AbortMonitoring
+ }
+ catch (const zen::FileError& e)
+ {
+ if (!reportErrorTimeout(e.toString())) //return true if timeout or user selected "retry", else abort
+ return SHOW_GUI;
}
- catch (StartSyncNowException&) {}
- }
- }
- catch (const ::AbortThisProcess& ab)
- {
- return ab.getCommand();
}
- catch (const zen::FileError& error)
+ catch (const AbortMonitoring& ab)
{
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR);
- return RESUME;
+ return ab.reasonCode_;
}
-
- return RESUME;
}
diff --git a/RealtimeSync/tray_menu.h b/RealtimeSync/tray_menu.h
index 21d26932..9c910694 100644
--- a/RealtimeSync/tray_menu.h
+++ b/RealtimeSync/tray_menu.h
@@ -13,13 +13,12 @@
namespace rts
{
-enum MonitorResponse
+enum AbortReason
{
- RESUME,
- QUIT
+ SHOW_GUI,
+ EXIT_APP
};
-
-MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty
+AbortReason startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty
}
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp
index 36ceb006..ee56bc7c 100644
--- a/RealtimeSync/watcher.cpp
+++ b/RealtimeSync/watcher.cpp
@@ -5,30 +5,31 @@
// **************************************************************************
#include "watcher.h"
+#include <set>
+#include <zen/tick_count.h>
#include <zen/file_handling.h>
#include <zen/stl_tools.h>
-#include <set>
-#include <ctime>
-#include <wx/timer.h>
-#include "../lib/resolve_path.h"
#include <zen/dir_watcher.h>
-#include <wx+/string_conv.h>
#include <zen/thread.h>
+#include <zen/assert_static.h>
+#include <wx+/string_conv.h>
+#include <wx/timer.h>
+#include "../lib/resolve_path.h"
//#include "../library/db_file.h" //SYNC_DB_FILE_ENDING -> complete file too much of a dependency; file ending too little to decouple into single header
//#include "../library/lock_holder.h" //LOCK_FILE_ENDING
-#include <wx/msgdlg.h>
using namespace zen;
+namespace
+{
+const std::int64_t TICKS_UPDATE_INTERVAL = rts::UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
+TickVal lastExec = getTicks();
+};
bool rts::updateUiIsAllowed()
{
- const std::clock_t CLOCK_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * CLOCKS_PER_SEC / 1000;
-
- static std::clock_t lastExec = 0;
- const std::clock_t now = std::clock(); //this is quite fast: 2 * 10^-5
-
- if (now - lastExec >= CLOCK_UPDATE_INTERVAL) //perform ui updates not more often than necessary
+ const TickVal now = getTicks(); //0 on error
+ if (now - lastExec >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary
{
lastExec = now;
return true;
@@ -36,29 +37,30 @@ bool rts::updateUiIsAllowed()
return false;
}
+
namespace
{
const int CHECK_DIR_INTERVAL = 1000; //1 second interval
-}
-rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError
+std::vector<Zstring> getFormattedDirs(const std::vector<Zstring>& dirs) //throw FileError
{
- std::set<Zstring, LessFilename> dirNamesFmt;
+ std::set<Zstring, LessFilename> tmp; //make unique
- std::for_each(dirNamesNonFmt.begin(), dirNamesNonFmt.end(),
- [&](const Zstring& dirnameNonFmt)
- {
- const Zstring& dirnameFmt = zen::getFormattedDirectoryName(dirnameNonFmt);
+ std::transform(dirs.begin(), dirs.end(), std::inserter(tmp, tmp.end()),
+ [](const Zstring& dirnameNonFmt) { return getFormattedDirectoryName(dirnameNonFmt); });
- if (dirnameFmt.empty())
- throw zen::FileError(_("A directory input field is empty."));
- dirNamesFmt.insert(dirnameFmt);
- });
- if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless
- throw zen::FileError(_("A directory input field is empty."));
+ return std::vector<Zstring>(tmp.begin(), tmp.end());
+}
+}
+rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError
+{
+ const std::vector<Zstring> dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError
+ if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless
+ throw zen::FileError(_("A directory 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;
@@ -67,16 +69,24 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
const Zstring& dirnameFmt = *iter;
try
{
+ //a non-existent network path may block, so check existence asynchronously!
+ auto ftDirExists = async([=] { return zen::dirExists(dirnameFmt); });
+ while (!ftDirExists.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)))
+ statusHandler.requestUiRefresh(); //may throw!
+ if (!ftDirExists.get())
+ return WaitResult(CHANGE_DIR_MISSING, dirnameFmt);
+
+
watches.push_back(std::make_pair(dirnameFmt, std::make_shared<DirWatcher>(dirnameFmt))); //throw FileError, ErrorNotExisting
}
catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!!
{
- return CHANGE_DIR_MISSING;
+ return WaitResult(CHANGE_DIR_MISSING, dirnameFmt);
}
catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing)
{
- if (!dirExists(dirnameFmt)) //not an atomic behavior!!!
- return CHANGE_DIR_MISSING;
+ if (!dirExists(dirnameFmt)) //file system race condition!!
+ return WaitResult(CHANGE_DIR_MISSING, dirnameFmt);
throw;
}
}
@@ -104,11 +114,11 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
//IMPORTANT CHECK: dirwatcher has problems detecting removal of top watched directories!
if (checkDirExistNow)
if (!dirExists(dirname)) //catch errors related to directory removal, e.g. ERROR_NETNAME_DELETED
- return CHANGE_DIR_MISSING;
+ return WaitResult(CHANGE_DIR_MISSING, dirname);
try
{
- std::vector<Zstring> changedFiles = watcher.getChanges([&] { statusHandler->requestUiRefresh(); }); //throw FileError, ErrorNotExisting
+ std::vector<Zstring> changedFiles = watcher.getChanges([&] { statusHandler.requestUiRefresh(); }); //throw FileError, ErrorNotExisting
//remove to be ignored changes
vector_remove_if(changedFiles, [](const Zstring& name)
@@ -130,67 +140,61 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
}
catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!!
{
- return CHANGE_DIR_MISSING;
+ return WaitResult(CHANGE_DIR_MISSING, dirname);
}
catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing)
{
- if (!dirExists(dirname)) //not an atomic behavior!!!
- return CHANGE_DIR_MISSING;
+ if (!dirExists(dirname)) //file system race condition!!
+ return WaitResult(CHANGE_DIR_MISSING, dirname);
throw;
}
}
- wxMilliSleep(rts::UI_UPDATE_INTERVAL);
- statusHandler->requestUiRefresh();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL));
+ statusHandler.requestUiRefresh();
}
}
//support for monitoring newly connected directories volumes (e.g.: USB-sticks)
-void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError
+void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError
{
- wxLongLong lastCheck;
-
while (true)
{
- const wxLongLong current = wxGetLocalTimeMillis();
- if (current - lastCheck >= CHECK_DIR_INTERVAL)
- {
- lastCheck = current;
+ //support specifying volume by name => call getFormattedDirectoryName() repeatedly
+ const std::vector<Zstring>& dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError
- auto ftDirMissing = async([=]() -> bool
+ bool allExisting = true;
+ for (auto iter = dirNamesFmt.begin(); iter != dirNamesFmt.end(); ++iter)
+ {
+ const Zstring dirnameFmt = *iter;
+ auto ftDirExisting = async([=]() -> bool
{
- return std::find_if(dirNamesNonFmt.begin(), dirNamesNonFmt.end(),
- [](const Zstring& dirnameNonFmt) -> bool
- {
- //support specifying volume by name => call getFormattedDirectoryName() repeatedly
- const Zstring dirnameFmt = zen::getFormattedDirectoryName(dirnameNonFmt);
-
- if (dirnameFmt.empty())
- throw zen::FileError(_("A directory input field is empty."));
#ifdef FFS_WIN
- //1. login to network share, if necessary
- loginNetworkShare(dirnameFmt, false); //login networks shares, no PW prompt -> is this really RTS's task?
+ //1. login to network share, if necessary -> we probably do NOT want multiple concurrent runs: GUI!?
+ loginNetworkShare(dirnameFmt, false); //login networks shares, no PW prompt -> is this really RTS's job?
#endif
- //2. check dir existence
- return !zen::dirExists(dirnameFmt);
- }) != dirNamesNonFmt.end();
+ //2. check dir existence
+ return zen::dirExists(dirnameFmt);
});
- while (!ftDirMissing.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL)))
- statusHandler->requestUiRefresh(); //may throw!
+ while (!ftDirExisting.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL)))
+ statusHandler.requestUiRefresh(); //may throw!
- try
+ if (!ftDirExisting.get())
{
- if (!ftDirMissing.get()) //throw X
- return;
- }
- catch (...) //boost::future seems to map async exceptions to "some" boost exception type -> migrate this for C++11
- {
- throw zen::FileError(_("A directory input field is empty."));
+ allExisting = false;
+ break;
}
}
+ if (allExisting)
+ return;
- wxMilliSleep(rts::UI_UPDATE_INTERVAL);
- statusHandler->requestUiRefresh();
+ //wait some time...
+ assert_static(CHECK_DIR_INTERVAL % UI_UPDATE_INTERVAL == 0);
+ for (int i = 0; i < CHECK_DIR_INTERVAL / UI_UPDATE_INTERVAL; ++i)
+ {
+ boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL));
+ statusHandler.requestUiRefresh();
+ }
}
}
diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h
index cb39ed20..17252535 100644
--- a/RealtimeSync/watcher.h
+++ b/RealtimeSync/watcher.h
@@ -14,8 +14,7 @@
namespace rts
{
-const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
-
+const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
bool updateUiIsAllowed();
@@ -33,19 +32,22 @@ enum ChangeType
CHANGE_DETECTED,
CHANGE_DIR_MISSING
};
+
struct WaitResult
{
- WaitResult(ChangeType tp, const Zstring& chgFile = Zstring()) : type(tp), filename(chgFile) {}
+ WaitResult(ChangeType tp, const Zstring& chgFile) : type(tp), filename(chgFile) {}
ChangeType type;
- Zstring filename; //filled if type == CHANGE_DETECTED
+ Zstring filename; //file or directory name
};
-WaitResult waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, //non-formatted dir names that yet require call to getFormattedDirectoryName()
- WaitCallback* statusHandler); //throw(FileError)
+
+WaitResult waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
+ //non-formatted dirnames that yet require call to getFormattedDirectoryName(); empty directories must be checked by caller!
+ WaitCallback& statusHandler); //throw FileError
//wait until all directories become available (again)
void waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt,
- WaitCallback* statusHandler); //throw(FileError)
+ WaitCallback& statusHandler); //throw FileError
}
#endif // WATCHER_H_INCLUDED
diff --git a/RealtimeSync/xml_ffs.cpp b/RealtimeSync/xml_ffs.cpp
index 6ec5f843..6572800b 100644
--- a/RealtimeSync/xml_ffs.cpp
+++ b/RealtimeSync/xml_ffs.cpp
@@ -46,7 +46,7 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat
}
-void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config) //throw xmlAccess::FfsXmlError;
+void rts::readRealOrBatchConfig(const Zstring& filename, xmlAccess::XmlRealConfig& config) //throw xmlAccess::FfsXmlError;
{
if (xmlAccess::getXmlType(filename) != xmlAccess::XML_TYPE_BATCH)
{
@@ -63,11 +63,11 @@ void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConf
catch (const xmlAccess::FfsXmlError& e)
{
if (e.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- config = convertBatchToReal(batchCfg, toZ(filename)); //do work despite parsing errors, then re-throw
+ config = convertBatchToReal(batchCfg, filename); //do work despite parsing errors, then re-throw
throw; //
}
- config = convertBatchToReal(batchCfg, toZ(filename));
+ config = convertBatchToReal(batchCfg, filename);
}
diff --git a/RealtimeSync/xml_ffs.h b/RealtimeSync/xml_ffs.h
index abff3c10..b63c3620 100644
--- a/RealtimeSync/xml_ffs.h
+++ b/RealtimeSync/xml_ffs.h
@@ -8,13 +8,14 @@
#define XMLFREEFILESYNC_H_INCLUDED
#include "xml_proc.h"
+#include <zen/zstring.h>
//reuse (some of) FreeFileSync's xml files
namespace rts
{
-void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::FfsXmlError);
+void readRealOrBatchConfig(const Zstring& filename, xmlAccess::XmlRealConfig& config); //throw FfsXmlError
int getProgramLanguage();
}
diff --git a/RealtimeSync/xml_proc.cpp b/RealtimeSync/xml_proc.cpp
index 4f9306d2..891cb2df 100644
--- a/RealtimeSync/xml_proc.cpp
+++ b/RealtimeSync/xml_proc.cpp
@@ -36,22 +36,22 @@ bool isXmlTypeRTS(const XmlDoc& doc) //throw()
}
-void xmlAccess::readRealConfig(const wxString& filename, XmlRealConfig& config)
+void xmlAccess::readRealConfig(const Zstring& filename, XmlRealConfig& config)
{
- if (!fileExists(toZ(filename)))
- throw FfsXmlError(_("File does not exist:") + L"\n\"" + toZ(filename) + L"\"");
+ if (!fileExists(filename))
+ throw FfsXmlError(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)));
XmlDoc doc;
- loadXmlDocument(toZ(filename), doc); //throw (FfsXmlError)
+ loadXmlDocument(filename, doc); //throw FfsXmlError
if (!isXmlTypeRTS(doc))
- throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + toZ(filename) + L"\"");
+ throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
XmlIn in(doc);
::readConfig(in, config);
if (in.errorsOccured())
- throw FfsXmlError(_("Configuration loaded partially only:") + L"\n\"" + toZ(filename) + L"\"\n\n" +
+ throw FfsXmlError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" +
getErrorMessageFormatted(in), FfsXmlError::WARNING);
}
@@ -67,7 +67,7 @@ void writeConfig(const XmlRealConfig& config, XmlOut& out)
}
-void xmlAccess::writeRealConfig(const XmlRealConfig& config, const wxString& filename)
+void xmlAccess::writeRealConfig(const XmlRealConfig& config, const Zstring& filename)
{
XmlDoc doc("FreeFileSync");
doc.root().setAttribute("XmlType", "REAL");
@@ -75,5 +75,5 @@ void xmlAccess::writeRealConfig(const XmlRealConfig& config, const wxString& fil
XmlOut out(doc);
writeConfig(config, out);
- saveXmlDocument(doc, toZ(filename)); //throw (FfsXmlError)
+ saveXmlDocument(doc, filename); //throw (FfsXmlError)
}
diff --git a/RealtimeSync/xml_proc.h b/RealtimeSync/xml_proc.h
index a2e178d4..e07f9844 100644
--- a/RealtimeSync/xml_proc.h
+++ b/RealtimeSync/xml_proc.h
@@ -9,6 +9,7 @@
#include <vector>
#include <wx/string.h>
+#include <zen/zstring.h>
#include "../lib/xml_base.h"
@@ -22,8 +23,8 @@ struct XmlRealConfig
size_t delay;
};
-void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::FfsXmlError);
-void writeRealConfig(const XmlRealConfig& config, const wxString& filename); //throw (xmlAccess::FfsXmlError);
+void readRealConfig(const Zstring& filename, XmlRealConfig& config); //throw FfsXmlError
+void writeRealConfig(const XmlRealConfig& config, const Zstring& filename); //throw FfsXmlError
}
#endif // XMLPROCESSING_H_INCLUDED
diff --git a/algorithm.cpp b/algorithm.cpp
index 3d440bb0..498539ad 100644
--- a/algorithm.cpp
+++ b/algorithm.cpp
@@ -11,7 +11,7 @@
#include <tuple>
#include "lib/resources.h"
#include <zen/file_handling.h>
-#include "lib/recycler.h"
+#include <zen/recycler.h>
#include <wx/msgdlg.h>
#include "lib/norm_filter.h"
#include <wx+/string_conv.h>
@@ -207,18 +207,13 @@ public:
{
if (lhs.shortName.empty())
return rhs.shortName.empty();
- else
- {
- if (rhs.shortName.empty())
- return false;
- else
- {
- 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;
- }
- }
+ 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:
@@ -276,21 +271,16 @@ public:
{
if (lhs.shortName.empty()) //test if object is existing at all
return rhs.shortName.empty();
- else
- {
- if (rhs.shortName.empty())
- return false;
- else
- {
- 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) &&
+ 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) &&
#ifdef FFS_WIN //comparison of symbolic link type is relevant for Windows only
- lhs.type == rhs.type &&
+ lhs.type == rhs.type &&
#endif
- lhs.targetPath == rhs.targetPath;
- }
- }
+ lhs.targetPath == rhs.targetPath;
}
private:
@@ -436,7 +426,7 @@ private:
//----------- detect renamed files -----------------
if (!exLeftOnly.empty() && !exRightOnly.empty())
{
- findEqualDbEntries(dirInfoLeft.baseDirContainer, //fill map "onceEqual"
+ findEqualDbEntries(dirInfoLeft .baseDirContainer, //fill map "onceEqual"
dirInfoRight.baseDirContainer);
detectRenamedFiles();
@@ -516,7 +506,7 @@ private:
else if (cat == FILE_RIGHT_SIDE_ONLY)
{
if (fileObj.getFileId<RIGHT_SIDE>() != FileId())
- exRightOnly.insert(std::make_pair(getAssocKey<RIGHT_SIDE>(fileObj), &fileObj));
+ exRightOnly.insert(std::make_pair(getFileIdKey<RIGHT_SIDE>(fileObj), &fileObj));
}
//----------------------------------------------------------------------
@@ -749,7 +739,7 @@ private:
if (entryLeft. second.id != FileId() &&
iterRight->second.id != FileId() &&
DataSetFile(entryLeft.first, entryLeft.second) == DataSetFile(iterRight->first, iterRight->second))
- onceEqual.insert(std::make_pair(getAssocKey(entryLeft.second), getAssocKey(iterRight->second)));
+ onceEqual.insert(std::make_pair(getFileIdKey(entryLeft.second), getFileIdKey(iterRight->second)));
}
});
@@ -762,12 +752,12 @@ private:
});
}
- typedef std::tuple<Int64, UInt64, FileId> AssocKey; //(date, size, file ID)
+ typedef std::tuple<Int64, UInt64, FileId> FileIdKey; //(date, size, file ID)
//modification date is *not* considered as part of container key, so check here!
template <class Container>
- static typename Container::const_iterator findValue(const Container& cnt, const AssocKey& key)
+ static typename Container::const_iterator findValue(const Container& cnt, const FileIdKey& key)
{
auto iterPair = cnt.equal_range(key); //since file id is already unique, we expect a single-element range at most
auto iter = std::find_if(iterPair.first, iterPair.second,
@@ -783,12 +773,12 @@ private:
std::for_each(exLeftOnly.begin(), exLeftOnly.end(),
[&](FileMapping* fileLeftOnly)
{
- const AssocKey& keyLeft = RedetermineAuto::getAssocKey<LEFT_SIDE>(*fileLeftOnly);
+ const FileIdKey& keyLeft = RedetermineAuto::getFileIdKey<LEFT_SIDE>(*fileLeftOnly);
auto iter = findValue(onceEqual, keyLeft);
if (iter != onceEqual.end())
{
- const AssocKey& keyRight = iter->second;
+ const FileIdKey& keyRight = iter->second;
auto iter2 = findValue(exRightOnly, keyRight);
if (iter2 != exRightOnly.end())
@@ -813,12 +803,12 @@ private:
//detection of renamed files
template <SelectedSide side>
- static AssocKey getAssocKey(const FileMapping& fsObj) { return std::make_tuple(fsObj.getLastWriteTime<side>(), fsObj.getFileSize<side>(), fsObj.getFileId<side>()); }
- static AssocKey getAssocKey(const FileDescriptor& fileDescr) { return std::make_tuple(fileDescr.lastWriteTimeRaw, fileDescr.fileSize, fileDescr.id); }
+ static FileIdKey getFileIdKey(const FileMapping& fsObj) { return std::make_tuple(fsObj.getLastWriteTime<side>(), fsObj.getFileSize<side>(), fsObj.getFileId<side>()); }
+ static FileIdKey getFileIdKey(const FileDescriptor& fileDescr) { return std::make_tuple(fileDescr.lastWriteTimeRaw, fileDescr.fileSize, fileDescr.id); }
- struct LessAssocKey
+ struct LessFileIdKey
{
- bool operator()(const AssocKey& lhs, const AssocKey& rhs) const
+ bool operator()(const FileIdKey& lhs, const FileIdKey& rhs) const
{
//caveat: *don't* allow 2 sec tolerance as container predicate!!
// => no strict weak ordering relation! reason: no transitivity of equivalence!
@@ -835,9 +825,9 @@ private:
std::vector<FileMapping*> exLeftOnly;
- std::multimap<AssocKey, AssocKey, LessAssocKey> onceEqual; //keys for left and right files which are considered "equal" by database
+ std::multimap<FileIdKey, FileIdKey, LessFileIdKey> onceEqual; //associates left and right database entries which are considered "equal" := "same name, size, date"
- std::multimap<AssocKey, FileMapping*, LessAssocKey> exRightOnly;
+ std::multimap<FileIdKey, FileMapping*, LessFileIdKey> exRightOnly;
/*
detect renamed files
@@ -851,15 +841,14 @@ private:
Algorithm:
----------
- DB-file left --- name, size, date ---> DB-file right
+ DB-file left --- (name, size, date) ---> DB-file right
/|\ |
- | file ID, size, date
- file ID, size, date |
+ | (file ID, size, date) | (file ID, size, date)
| \|/
- X Y
+ file left only file right only
FAT caveat: File Ids are generally not stable when file is either moved or renamed!
- => 1. Move/rename operations on FAT cannot be detected.
+ => 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
*/
};
diff --git a/comparison.cpp b/comparison.cpp
index 15cd25fb..5b359e38 100644
--- a/comparison.cpp
+++ b/comparison.cpp
@@ -94,7 +94,7 @@ void determineExistentDirs(const std::set<Zstring, LessFilename>& dirnames,
if (tryReportingError([&]
{
if (!dirExistsUpdating(dirname, allowUserInteraction, procCallback))
- throw FileError(_("Directory does not exist:") + L"\n" + L"\"" + dirname + L"\"" + L" \n\n" +
+ throw FileError(replaceCpy(_("Cannot find directory %x."), L"%x", fmtFileName(dirname)) + L"\n\n" +
_("You can ignore this error to consider the directory as empty."));
}, procCallback))
dirnamesExisting.insert(dirname);
@@ -107,8 +107,7 @@ void determineExistentDirs(const std::set<Zstring, LessFilename>& dirnames,
//similar check if one directory is read/written by multiple pairs not before beginning of synchronization
std::wstring checkFolderDependency(const std::vector<FolderPairCfg>& folderPairsForm) //returns warning message, empty if all ok
{
- typedef std::vector<std::pair<std::wstring, std::wstring> > DirDirList;
- DirDirList dependentDirs;
+ std::vector<std::pair<Zstring, Zstring>> dependentDirs;
auto dependentDir = [](const Zstring& lhs, const Zstring& rhs)
{
@@ -120,7 +119,7 @@ std::wstring checkFolderDependency(const std::vector<FolderPairCfg>& folderPairs
if (!i->leftDirectoryFmt.empty() && !i->rightDirectoryFmt.empty()) //empty folders names may be accepted by user
{
if (dependentDir(i->leftDirectoryFmt, i->rightDirectoryFmt)) //test wheter leftDirectory begins with rightDirectory or the other way round
- dependentDirs.push_back(std::make_pair(utf8CvrtTo<std::wstring>(i->leftDirectoryFmt), utf8CvrtTo<std::wstring>(i->rightDirectoryFmt)));
+ dependentDirs.push_back(std::make_pair(i->leftDirectoryFmt, i->rightDirectoryFmt));
}
std::wstring warningMsg;
@@ -129,9 +128,9 @@ std::wstring checkFolderDependency(const std::vector<FolderPairCfg>& folderPairs
{
warningMsg = _("Directories are dependent! Be careful when setting up synchronization rules:");
for (auto i = dependentDirs.begin(); i != dependentDirs.end(); ++i)
- warningMsg += std::wstring(L"\n\n") +
- L"\"" + i->first + L"\"\n" +
- L"\"" + i->second + L"\"";
+ warningMsg += L"\n\n" +
+ fmtFileName(i->first) + L"\n" +
+ fmtFileName(i->second);
}
return warningMsg;
}
@@ -145,11 +144,11 @@ public:
pc_(pc),
bytesReported_(bytesReported) {}
- virtual void updateCompareStatus(UInt64 totalBytesTransferred)
+ virtual void updateCompareStatus(UInt64 totalBytes)
{
//inform about the (differential) processed amount of data
- pc_.updateProcessedData(0, to<Int64>(totalBytesTransferred) - to<Int64>(bytesReported_)); //throw()! -> this ensures client and service provider are in sync!
- bytesReported_ = totalBytesTransferred; //
+ pc_.updateProcessedData(0, to<Int64>(totalBytes) - to<Int64>(bytesReported_)); //throw()! -> this ensures client and service provider are in sync!
+ bytesReported_ = totalBytes; //
pc_.requestUiRefresh(); //may throw
}
@@ -203,15 +202,10 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& cfgLi
PreventStandby dummy2;
(void)dummy2;
- /*
- #ifdef NDEBUG
- wxLogNull noWxLogs; //hide wxWidgets log messages in release build
- #endif
- */
//PERF_START;
//init process: keep at beginning so that all gui elements are initialized properly
- procCallback.initNewProcess(-1, 0, ProcessCallback::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects
+ procCallback.initNewPhase(-1, 0, ProcessCallback::PHASE_SCANNING); //it's not known how many files will be scanned => -1 objects
//-------------------some basic checks:------------------------------------------
@@ -358,10 +352,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& cfgLi
//check for very old dates or date2s in the future
std::wstring getConflictInvalidDate(const Zstring& fileNameFull, Int64 utcTime)
{
- std::wstring msg = _("File %x has an invalid date!");
- replace(msg, L"%x", std::wstring(L"\"") + fileNameFull + L"\"");
- msg += L"\n\n" + _("Date") + L": " + utcToLocalTimeString(utcTime);
- return _("Conflict detected:") + L"\n" + msg;
+ return _("Conflict detected:") + L"\n" +
+ replaceCpy(_("File %x has an invalid date!"), L"%x", fmtFileName(fileNameFull)) + L"\n\n" +
+ _("Date") + L": " + utcToLocalTimeString(utcTime);
}
@@ -370,12 +363,10 @@ namespace
//check for changed files with same modification date
std::wstring getConflictSameDateDiffSize(const FileMapping& fileObj)
{
- std::wstring msg = _("Files %x have the same date but a different size!");
- replace(msg, L"%x", std::wstring(L"\"") + fileObj.getRelativeName<LEFT_SIDE>() + L"\"");
- msg += L"\n\n";
- msg += L"<-- " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime<LEFT_SIDE >()) + L" " + _("Size") + L": " + toStringSep(fileObj.getFileSize<LEFT_SIDE>()) + L"\n";
- msg += L"--> " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size") + L": " + toStringSep(fileObj.getFileSize<RIGHT_SIDE>());
- return _("Conflict detected:") + L"\n" + msg;
+ 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": " + toStringSep(fileObj.getFileSize<LEFT_SIDE>()) + L"\n" +
+ L"--> " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size") + L": " + toStringSep(fileObj.getFileSize<RIGHT_SIDE>());
}
}
@@ -419,11 +410,8 @@ void CompareProcess::categorizeSymlinkByTime(SymLinkMapping& linkObj) const
linkObj.setCategory<SYMLINK_DIFFERENT_METADATA>();
}
else
- {
- std::wstring conflictMsg = _("Conflict detected:") + L"\n" + _("Symlinks %x have the same date but a different target!");
- replace(conflictMsg, L"%x", std::wstring(L"\"") + linkObj.getRelativeName<LEFT_SIDE>() + L"\"");
- linkObj.setCategoryConflict(conflictMsg);
- }
+ linkObj.setCategoryConflict(_("Conflict detected:") + L"\n" +
+ replaceCpy(_("Symbolic links %x have the same date but a different target."), L"%x", fmtFileName(linkObj.getObjRelativeName())));
break;
case CmpFileTime::TIME_LEFT_NEWER:
@@ -557,24 +545,24 @@ void CompareProcess::compareByContent(std::vector<std::pair<FolderPairCfg, BaseD
filesToCompareBytewise.push_back(fileObj);
});
- const size_t objectsTotal = filesToCompareBytewise.size() * 2;
- const UInt64 bytesTotal = //left and right filesizes should be the same
- 2U * std::accumulate(filesToCompareBytewise.begin(), filesToCompareBytewise.end(), static_cast<UInt64>(0),
+ const size_t objectsTotal = filesToCompareBytewise.size();
+ const UInt64 bytesTotal = //left and right filesizes are equal
+ std::accumulate(filesToCompareBytewise.begin(), filesToCompareBytewise.end(), static_cast<UInt64>(0),
[](UInt64 sum, FileMapping* fsObj) { return sum + fsObj->getFileSize<LEFT_SIDE>(); });
- procCallback.initNewProcess(static_cast<int>(objectsTotal),
- to<Int64>(bytesTotal),
- ProcessCallback::PROCESS_COMPARING_CONTENT);
+ procCallback.initNewPhase(static_cast<int>(objectsTotal),
+ 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);
+ const std::wstring txtComparingContentOfFiles = replaceCpy(_("Comparing content of files %x"), L"%x", L"\n%x", false);
//compare files (that have same size) bytewise...
std::for_each(filesToCompareBytewise.begin(), filesToCompareBytewise.end(),
[&](FileMapping* fileObj)
{
- procCallback.reportStatus(replaceCpy(txtComparingContentOfFiles, L"%x", utf8CvrtTo<std::wstring>(fileObj->getRelativeName<LEFT_SIDE>()), false));
+ procCallback.reportStatus(replaceCpy(txtComparingContentOfFiles, L"%x", fmtFileName(fileObj->getObjRelativeName()), false));
//check files that exist in left and right model but have different content
@@ -582,7 +570,7 @@ void CompareProcess::compareByContent(std::vector<std::pair<FolderPairCfg, BaseD
{
if (filesHaveSameContentUpdating(fileObj->getFullName<LEFT_SIDE>(), //throw FileError
fileObj->getFullName<RIGHT_SIDE>(),
- fileObj->getFileSize<LEFT_SIDE>() * 2U,
+ fileObj->getFileSize<LEFT_SIDE >(),
procCallback))
{
if (fileObj->getShortName<LEFT_SIDE>() == fileObj->getShortName<RIGHT_SIDE>() &&
@@ -595,11 +583,12 @@ void CompareProcess::compareByContent(std::vector<std::pair<FolderPairCfg, BaseD
else
fileObj->setCategory<FILE_DIFFERENT>();
- procCallback.updateProcessedData(2, 0); //processed data is communicated in subfunctions!
- procCallback.requestUiRefresh(); //may throw
+ procCallback.updateProcessedData(1, 0); //processed data is communicated in subfunctions!
}, procCallback))
fileObj->setCategoryConflict(_("Conflict detected:") + L"\n" + _("Comparing files by content failed."));
+
+ procCallback.requestUiRefresh(); //may throw
});
}
diff --git a/comparison.h b/comparison.h
index 28d666c7..7dc18682 100644
--- a/comparison.h
+++ b/comparison.h
@@ -7,7 +7,7 @@
#ifndef COMPARISON_H_INCLUDED
#define COMPARISON_H_INCLUDED
-#include <zen/process_status.h>
+#include <zen/process_priority.h>
#include "file_hierarchy.h"
#include "lib/process_xml.h"
#include "process_callback.h"
diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp
index f1bb7385..5a18ddbe 100644
--- a/file_hierarchy.cpp
+++ b/file_hierarchy.cpp
@@ -7,6 +7,7 @@
#include "file_hierarchy.h"
#include <zen/i18n.h>
#include <zen/utf8.h>
+#include <zen/file_error.h>
using namespace zen;
@@ -373,11 +374,11 @@ std::wstring zen::getSyncOpDescription(const FileSystemObject& fsObj)
return getSyncOpDescription(op) + L"\n" +
(EqualFilename()(beforeLast(relSource, FILE_NAME_SEPARATOR), beforeLast(relTarget, FILE_NAME_SEPARATOR)) ? //returns empty string if ch not found
//detected pure "rename"
- L"\"" + utf8CvrtTo<std::wstring>(afterLast(relSource, FILE_NAME_SEPARATOR)) + L"\"" + L" ->\n" + //show short name only
- L"\"" + utf8CvrtTo<std::wstring>(afterLast(relTarget, FILE_NAME_SEPARATOR)) + L"\"" :
+ fmtFileName(afterLast(relSource, FILE_NAME_SEPARATOR)) + L" ->\n" + //show short name only
+ fmtFileName(afterLast(relTarget, FILE_NAME_SEPARATOR)) :
//"move" or "move + rename"
- L"\"" + utf8CvrtTo<std::wstring>(relSource) + L"\"" + L" ->\n" +
- L"\"" + utf8CvrtTo<std::wstring>(relTarget) + L"\"");
+ fmtFileName(relSource) + L" ->\n" +
+ fmtFileName(relTarget));
//attention: ::SetWindowText() doesn't handle tab characters correctly in combination with certain file names, so don't use them
}
break;
diff --git a/file_hierarchy.h b/file_hierarchy.h
index e41992a3..4f1c549a 100644
--- a/file_hierarchy.h
+++ b/file_hierarchy.h
@@ -228,9 +228,9 @@ public:
#ifdef _MSC_VER
#pragma warning(default : 4355)
#endif
- baseDirPfL(dirPostfixedLeft),
- baseDirPfR(dirPostfixedRight),
- dirExistsLeft_(dirExistsLeft),
+ baseDirPfL (dirPostfixedLeft ),
+ baseDirPfR (dirPostfixedRight),
+ dirExistsLeft_ (dirExistsLeft ),
dirExistsRight_(dirExistsRight) {}
template <SelectedSide side> const Zstring& getBaseDirPf() const; //base sync directory postfixed with FILE_NAME_SEPARATOR
@@ -482,7 +482,6 @@ public:
template <SelectedSide side> Int64 getLastWriteTime() const;
template <SelectedSide side> UInt64 getFileSize () const;
template <SelectedSide side> FileId getFileId () const;
- template <SelectedSide side> const Zstring getExtension() const;
void setMoveRef(ObjectId refId) { moveFileRef = refId; } //reference to corresponding renamed file
ObjectId getMoveRef() const { return moveFileRef; } //may be nullptr
@@ -1098,19 +1097,6 @@ FileId FileMapping::getFileId<RIGHT_SIDE>() const
}
-template <SelectedSide side> inline
-const Zstring FileMapping::getExtension() const
-{
- //attention: Zstring::AfterLast() returns whole string if char not found! -> don't use
- const Zstring& shortName = getShortName<side>();
-
- const size_t pos = shortName.rfind(Zchar('.'));
- return pos == Zstring::npos ?
- Zstring() :
- Zstring(shortName.c_str() + pos + 1);
-}
-
-
template <> inline
void FileMapping::syncTo<LEFT_SIDE>(const FileDescriptor& descrTarget, const FileDescriptor* descrSource) //copy + update file attributes
{
diff --git a/lib/IFileOperation/file_op.cpp b/lib/IFileOperation/file_op.cpp
deleted file mode 100644
index 3d7717f4..00000000
--- a/lib/IFileOperation/file_op.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-// **************************************************************************
-// * 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 "file_op.h"
-#include <algorithm>
-#include <string>
-#define WIN32_LEAN_AND_MEAN
-#include <zen/com_ptr.h>
-#include <zen/com_error.h>
-
-#include <shellapi.h> //shell constants such as FO_* values
-#include <shobjidl.h>
-
-using namespace zen;
-
-
-namespace
-{
-void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
- size_t fileNo) //size of fileNames array
-{
- ComPtr<IFileOperation> fileOp;
- ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
- nullptr,
- CLSCTX_ALL,
- IID_PPV_ARGS(fileOp.init())));
-
- // Set the operation flags. Turn off all UI
- // from being shown to the user during the
- // operation. This includes error, confirmation
- // and progress dialogs.
- ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_ALLOWUNDO | //throw ComError
- FOF_NOCONFIRMATION |
- FOF_SILENT |
- FOFX_EARLYFAILURE |
- FOF_NOERRORUI));
-
- int operationCount = 0;
-
- for (size_t i = 0; i < fileNo; ++i)
- {
- //create file/folder item object
- ComPtr<IShellItem> psiFile;
- HRESULT hr = ::SHCreateItemFromParsingName(fileNames[i],
- nullptr,
- IID_PPV_ARGS(psiFile.init()));
- if (FAILED(hr))
- {
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore
- hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
- continue;
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr);
- }
-
- ZEN_CHECK_COM(fileOp->DeleteItem(psiFile.get(), nullptr));
-
- ++operationCount;
- }
-
- if (operationCount == 0) //calling PerformOperations() without anything to do would result in E_UNEXPECTED
- return;
-
- //perform actual operations
- ZEN_CHECK_COM(fileOp->PerformOperations());
-
- //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
- BOOL pfAnyOperationsAborted = FALSE;
- ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
-
- if (pfAnyOperationsAborted == TRUE)
- throw ComError(L"Operation did not complete successfully.");
-}
-
-
-void copyFile(const wchar_t* sourceFile, //throw ComError
- const wchar_t* targetFile)
-{
- ComPtr<IFileOperation> fileOp;
- ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
- nullptr,
- CLSCTX_ALL,
- IID_PPV_ARGS(fileOp.init())));
-
- // Set the operation flags. Turn off all UI
- // from being shown to the user during the
- // operation. This includes error, confirmation
- // and progress dialogs.
- ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw ComError
- FOF_SILENT |
- FOFX_EARLYFAILURE |
- FOF_NOERRORUI));
- //create source object
- ComPtr<IShellItem> psiSourceFile;
- {
- HRESULT hr = ::SHCreateItemFromParsingName(sourceFile,
- nullptr,
- IID_PPV_ARGS(psiSourceFile.init()));
- if (FAILED(hr))
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr);
- }
-
- const size_t pos = std::wstring(targetFile).find_last_of(L'\\');
- if (pos == std::wstring::npos)
- throw ComError(L"Target filename does not contain a path separator.");
-
- const std::wstring targetFolder(targetFile, pos);
- const std::wstring targetFileNameShort = targetFile + pos + 1;
-
- //create target folder object
- ComPtr<IShellItem> psiTargetFolder;
- {
- HRESULT hr = ::SHCreateItemFromParsingName(targetFolder.c_str(),
- nullptr,
- IID_PPV_ARGS(psiTargetFolder.init()));
- if (FAILED(hr))
- throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr);
- }
-
- //schedule file copy operation
- ZEN_CHECK_COM(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), nullptr));
-
- //perform actual operations
- ZEN_CHECK_COM(fileOp->PerformOperations());
-
- //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
- BOOL pfAnyOperationsAborted = FALSE;
- ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
-
- if (pfAnyOperationsAborted == TRUE)
- throw ComError(L"Operation did not complete successfully.");
-}
-
-
-inline
-void copyString(const std::wstring& input, wchar_t* buffer, size_t bufferSize)
-{
- if (bufferSize > 0)
- {
- //size_t endPos = input.copy(buffer, bufferSize - 1);
- //buffer[endPos] = 0;
- const size_t maxSize = std::min(input.length(), bufferSize - 1);
- std::copy(input.begin(), input.begin() + maxSize, buffer);
- buffer[maxSize] = 0;
- }
-}
-
-std::wstring lastErrorMessage; //this should really be thread-local!!!
-}
-
-
-bool fileop::moveToRecycleBin(const wchar_t* fileNames[],
- size_t fileNo) //size of fileNames array
-{
- try
- {
- ::moveToRecycleBin(fileNames, fileNo); //throw ComError
- return true;
- }
- catch (const zen::ComError& e)
- {
- lastErrorMessage = e.toString();
- return false;
- }
-}
-
-
-bool fileop::copyFile(const wchar_t* sourceFile,
- const wchar_t* targetFile)
-{
- try
- {
- ::copyFile(sourceFile, targetFile); //throw ComError
- return true;
- }
- catch (const zen::ComError& e)
- {
- lastErrorMessage = e.toString();
- return false;
- }
-}
-
-
-//if any of the functions above returns 'false', this message returns last error
-void fileop::getLastError(wchar_t* errorMessage, size_t errorBufferLen)
-{
- copyString(lastErrorMessage, errorMessage, errorBufferLen);
-}
diff --git a/lib/ShadowCopy/LockFile.cpp b/lib/ShadowCopy/LockFile.cpp
index b9008863..aac4c170 100644
--- a/lib/ShadowCopy/LockFile.cpp
+++ b/lib/ShadowCopy/LockFile.cpp
@@ -20,10 +20,9 @@ int wmain(int argc, wchar_t* argv[])
}
std::wstring filename = argv[1];
- //obtain exclusive lock on test file
HANDLE hFile = ::CreateFile(filename.c_str(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
+ GENERIC_READ,
+ 0, //obtain *exclusive* lock on test file
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
diff --git a/lib/ShadowCopy/Shadow_Server2003.vcxproj b/lib/ShadowCopy/Shadow_Server2003.vcxproj
index a893a389..ad24d4c1 100644
--- a/lib/ShadowCopy/Shadow_Server2003.vcxproj
+++ b/lib/ShadowCopy/Shadow_Server2003.vcxproj
@@ -99,7 +99,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -111,6 +111,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -132,7 +133,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -144,6 +145,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -163,7 +165,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -177,6 +179,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -199,7 +202,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -213,6 +216,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
diff --git a/lib/ShadowCopy/Shadow_Windows7.vcxproj b/lib/ShadowCopy/Shadow_Windows7.vcxproj
index 2392fa99..5381372b 100644
--- a/lib/ShadowCopy/Shadow_Windows7.vcxproj
+++ b/lib/ShadowCopy/Shadow_Windows7.vcxproj
@@ -99,7 +99,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -111,6 +111,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -131,7 +132,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_WINDOWS7;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
@@ -144,6 +145,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -163,7 +165,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -177,6 +179,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -198,7 +201,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_WINDOWS7;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
@@ -213,6 +216,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
diff --git a/lib/ShadowCopy/Shadow_XP.vcxproj b/lib/ShadowCopy/Shadow_XP.vcxproj
index e49e8941..fce942d5 100644
--- a/lib/ShadowCopy/Shadow_XP.vcxproj
+++ b/lib/ShadowCopy/Shadow_XP.vcxproj
@@ -99,7 +99,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -111,6 +111,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -133,7 +134,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -145,6 +146,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -164,7 +166,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -178,6 +180,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -200,7 +203,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -214,6 +217,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp
index bc27e2c3..c47ce983 100644
--- a/lib/ShadowCopy/shadow.cpp
+++ b/lib/ShadowCopy/shadow.cpp
@@ -10,6 +10,7 @@
#include <zen/com_ptr.h>
#include <zen/com_error.h>
#include <zen/scope_guard.h>
+#include <boost/thread/tss.hpp>
#ifdef USE_SHADOW_XP
#include "xp/inc/vss.h"
@@ -74,21 +75,6 @@ std::wstring formatVssError(HRESULT hr) //at least the one's from IVssBackupComp
}
-
-inline
-void copyString(const std::wstring& input, wchar_t* buffer, size_t bufferSize)
-{
- if (bufferSize > 0)
- {
- //size_t endPos = input.copy(buffer, bufferSize - 1);
- //buffer[endPos] = 0;
- const size_t maxSize = std::min(input.length(), bufferSize - 1);
- std::copy(input.begin(), input.begin() + maxSize, buffer);
- buffer[maxSize] = 0;
- }
-}
-
-
shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
{
ComPtr<IVssBackupComponents> backupComp;
@@ -156,12 +142,12 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
//finally: write volume name of newly created shadow copy
return shadow::ShadowData(backupComp, props.m_pwszSnapshotDeviceObject);
}
+
+boost::thread_specific_ptr<std::wstring> lastErrorMessage; //use "thread_local" in C++11
}
-shadow::ShadowHandle shadow::createShadowCopy(const wchar_t* volumeName,
- wchar_t* errorMessage,
- unsigned int errorBufferLen)
+shadow::ShadowHandle shadow::createShadowCopy(const wchar_t* volumeName)
{
try
{
@@ -170,17 +156,15 @@ shadow::ShadowHandle shadow::createShadowCopy(const wchar_t* volumeName,
}
catch (const zen::ComError& e)
{
- copyString(e.toString(), errorMessage, errorBufferLen);
+ lastErrorMessage.reset(new std::wstring(e.toString()));
return nullptr;
}
}
-void shadow::getShadowVolume(shadow::ShadowHandle handle,
- wchar_t* buffer,
- unsigned int bufferLen)
+const wchar_t* shadow::getShadowVolume(shadow::ShadowHandle handle)
{
- copyString(handle->shadowVolume_, buffer, bufferLen);
+ return handle ? handle->shadowVolume_.c_str() : nullptr; //better fail in client code than here!
}
@@ -188,3 +172,9 @@ void shadow::releaseShadowCopy(ShadowHandle handle)
{
delete handle;
}
+
+
+const wchar_t* shadow::getLastError()
+{
+ return !lastErrorMessage.get() ? L"" : lastErrorMessage->c_str();
+}
diff --git a/lib/ShadowCopy/shadow.h b/lib/ShadowCopy/shadow.h
index ea113dae..66d29300 100644
--- a/lib/ShadowCopy/shadow.h
+++ b/lib/ShadowCopy/shadow.h
@@ -31,44 +31,37 @@ typedef ShadowData* ShadowHandle;
//volumeName *must* end with "\"
SHADOWDLL_API
-ShadowHandle createShadowCopy(const wchar_t* volumeName, // in Returns nullptr on failure!
- wchar_t* errorMessage, // out
- unsigned int errorBufferLen); // in
+ShadowHandle createShadowCopy(const wchar_t* volumeName); //returns nullptr on failure!
-//don't forget to release the backupHandle after shadow copy is not needed anymore!
+//release the backupHandle after shadow copy is not needed anymore!
SHADOWDLL_API
void releaseShadowCopy(ShadowHandle handle);
SHADOWDLL_API
-void getShadowVolume(ShadowHandle handle, //shadowVolName does *not* end with "\"
- wchar_t* buffer,
- unsigned int bufferLen);
+const wchar_t* getShadowVolume(ShadowHandle handle); //never fails, returns shadowVolName, never ending with "\"
+//get last error message if any of the functions above fail
+SHADOWDLL_API
+const wchar_t* getLastError(); //no nullptr check required!
//##########################################################################################
/*----------
|typedefs|
----------*/
-typedef ShadowHandle (*CreateShadowCopyFct)(const wchar_t* volumeName,
- wchar_t* errorMessage,
- unsigned int errorBufferLen);
-
-typedef void (*ReleaseShadowCopyFct)(ShadowHandle handle);
-
-typedef void (*GetShadowVolumeFct)(ShadowHandle handle,
- wchar_t* buffer,
- unsigned int bufferLen);
-
+typedef ShadowHandle (*FunType_createShadowCopy )(const wchar_t* volumeName);
+typedef void (*FunType_releaseShadowCopy)(ShadowHandle handle);
+typedef const wchar_t* (*FunType_getShadowVolume )(ShadowHandle handle);
+typedef const wchar_t* (*FunType_getLastError)();
/*--------------
|symbol names|
--------------*/
//(use const pointers to ensure internal linkage)
-const char createShadowCopyFctName [] = "createShadowCopy";
-const char releaseShadowCopyFctName[] = "releaseShadowCopy";
-const char getShadowVolumeFctName [] = "getShadowVolume";
-
+const char funName_createShadowCopy [] = "createShadowCopy";
+const char funName_releaseShadowCopy[] = "releaseShadowCopy";
+const char funName_getShadowVolume [] = "getShadowVolume";
+const char funName_getLastError [] = "getLastError";
/*---------------
|library names|
---------------*/
diff --git a/lib/Thumbnail/thumbnail.cpp b/lib/Thumbnail/thumbnail.cpp
index 0176f89b..d35f15c3 100644
--- a/lib/Thumbnail/thumbnail.cpp
+++ b/lib/Thumbnail/thumbnail.cpp
@@ -27,22 +27,22 @@ thumb::HICON thumb::getThumbnail(const wchar_t* filename, int requestedSize) //r
{
const std::wstring filenameStr(filename);
- ComPtr<IShellFolder> shellFolder;
+ ComPtr<IShellFolder> desktopFolder;
{
- HRESULT hr = ::SHGetDesktopFolder(shellFolder.init());
- if (FAILED(hr) || !shellFolder)
+ HRESULT hr = ::SHGetDesktopFolder(desktopFolder.init());
+ if (FAILED(hr) || !desktopFolder)
return nullptr;
}
PIDLIST_RELATIVE pidlFolder = nullptr;
{
- const std::wstring& pathName = beforeLast(filenameStr, '\\');
- HRESULT hr = shellFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
- nullptr, // [in] IBindCtx *pbc,
- const_cast<LPWSTR>(pathName.c_str()), // [in] LPWSTR pszDisplayName,
- nullptr, // [out] ULONG *pchEaten,
- &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
- nullptr); // [in, out] ULONG *pdwAttributes
+ const std::wstring& pathName = beforeLast(filenameStr, L'\\');
+ HRESULT hr = desktopFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
+ nullptr, // [in] IBindCtx *pbc,
+ const_cast<LPWSTR>(pathName.c_str()), // [in] LPWSTR pszDisplayName,
+ nullptr, // [out] ULONG *pchEaten,
+ &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
+ nullptr); // [in, out] ULONG *pdwAttributes
if (FAILED(hr) || !pidlFolder)
return nullptr;
}
@@ -50,16 +50,16 @@ thumb::HICON thumb::getThumbnail(const wchar_t* filename, int requestedSize) //r
ComPtr<IShellFolder> imageFolder;
{
- HRESULT hr = shellFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
- nullptr,
- IID_PPV_ARGS(imageFolder.init()));
+ HRESULT hr = desktopFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
+ nullptr, // [in] IBindCtx *pbc,
+ IID_PPV_ARGS(imageFolder.init()));
if (FAILED(hr) || !imageFolder)
return nullptr;
}
PIDLIST_RELATIVE pidImage = nullptr;
{
- const std::wstring& shortName = afterLast(filenameStr, '\\');
+ const std::wstring& shortName = afterLast(filenameStr, L'\\');
HRESULT hr = imageFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
nullptr, // [in] IBindCtx *pbc,
const_cast<LPWSTR>(shortName.c_str()), // [in] LPWSTR pszDisplayName,
diff --git a/lib/Thumbnail/thumbnail.h b/lib/Thumbnail/thumbnail.h
index b8b95d8f..6c3575b5 100644
--- a/lib/Thumbnail/thumbnail.h
+++ b/lib/Thumbnail/thumbnail.h
@@ -49,15 +49,15 @@ HICON getIconByIndex(int iconIndex, int shilIconType); //return 0 on failure, ca
/*----------
|typedefs|
----------*/
-typedef HICON (*GetThumbnailFct )(const wchar_t* filename, int requestedSize);
-typedef HICON (*GetIconByIndexFct)(int iconIndex, int shilIconType);
+typedef HICON (*FunType_getThumbnail )(const wchar_t* filename, int requestedSize);
+typedef HICON (*FunType_getIconByIndex)(int iconIndex, int shilIconType);
/*--------------
|symbol names|
--------------*/
//(use const pointers to ensure internal linkage)
-const char getThumbnailFctName [] = "getThumbnail";
-const char getIconByIndexFctName [] = "getIconByIndex";
+const char funName_getThumbnail [] = "getThumbnail";
+const char funName_getIconByIndex[] = "getIconByIndex";
/*---------------
|library names|
diff --git a/lib/binary.cpp b/lib/binary.cpp
index 1da93ee6..c01bb4d2 100644
--- a/lib/binary.cpp
+++ b/lib/binary.cpp
@@ -113,12 +113,12 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
return false;
- bytesCompared += length1 * 2;
+ bytesCompared += length1;
callback.updateCompareStatus(bytesCompared); //send progress updates
}
while (!file1.eof());
- if (!file2.eof()) //highly unlikely, but theoretically possible! (but then again, not in this context where both files have same size...)
+ if (!file2.eof()) //highly unlikely, but possible! (but then again, not in this context where both files have same size...)
return false;
return true;
diff --git a/lib/binary.h b/lib/binary.h
index 1fcfdf57..b419e9e2 100644
--- a/lib/binary.h
+++ b/lib/binary.h
@@ -19,7 +19,7 @@ class CompareCallback
{
public:
virtual ~CompareCallback() {}
- virtual void updateCompareStatus(zen::UInt64 totalBytesTransferred) = 0;
+ virtual void updateCompareStatus(zen::UInt64 totalBytes) = 0;
};
bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError
diff --git a/lib/db_file.cpp b/lib/db_file.cpp
index 8ae8f94b..1bc75d82 100644
--- a/lib/db_file.cpp
+++ b/lib/db_file.cpp
@@ -66,7 +66,7 @@ public:
CheckedDbReader(wxInputStream& stream, const Zstring& errorObjName) : CheckedReader(stream), errorObjName_(errorObjName) {}
private:
- virtual void throwException() const { throw FileError(_("Error reading from synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); }
+ virtual void throwException() const { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(errorObjName_))); }
const Zstring errorObjName_;
};
@@ -77,7 +77,8 @@ class CheckedDbWriter : public CheckedWriter
public:
CheckedDbWriter(wxOutputStream& stream, const Zstring& errorObjName) : CheckedWriter(stream), errorObjName_(errorObjName) {}
- virtual void throwException() const { throw FileError(_("Error writing to synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); }
+private:
+ virtual void throwException() const { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(errorObjName_))); }
const Zstring errorObjName_;
};
@@ -96,7 +97,7 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
rawStream.Read(formatDescr, sizeof(formatDescr)); //throw FileError
if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr))
- throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\"");
+ throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB);
@@ -104,7 +105,7 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
std::int32_t version = cr.readPOD<std::int32_t>();
if (version != FILE_FORMAT_VER) //read file format version#
- throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\"");
+ throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
//read stream lists
StreamMapping output;
@@ -122,13 +123,12 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
}
catch (ErrorNotExisting&)
{
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
- _("One of the FreeFileSync database files is not yet existing:") + L" \n" +
- L"\"" + filename + L"\"");
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
+ replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename)));
}
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
+ catch (const std::bad_alloc& e)
{
- throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)");
+ throw FileError(_("Out of memory!") + L" " + utf8CvrtTo<std::wstring>(e.what()));
}
}
@@ -146,9 +146,9 @@ public:
StreamParser(buffer, fileName, *dirInfo); //throw FileError
return dirInfo;
}
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
+ catch (const std::bad_alloc& e)
{
- throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)");
+ throw FileError(_("Out of memory!") + L" " + utf8CvrtTo<std::wstring>(e.what()));
}
}
@@ -168,9 +168,9 @@ private:
assert_static(sizeof(FileId().first ) <= sizeof(std::uint64_t));
assert_static(sizeof(FileId().second) <= sizeof(std::uint64_t));
- const auto devId = static_cast<decltype(FileId().first )>(readPOD<std::uint64_t>()); //
- const auto fId = static_cast<decltype(FileId().second)>(readPOD<std::uint64_t>()); //silence "loss of precision" compiler warnings
- return std::make_pair(devId, fId);
+ 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);
}
void recurse(DirContainer& dirCont) const
@@ -438,10 +438,8 @@ std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMa
}
}
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
- _("Database files do not share a common synchronization session:") + L" \n" +
- L"\"" + fileNameLeft + L"\"\n" +
- L"\"" + fileNameRight + L"\"");
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
+ _("Database files do not share a common session."));
}
diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h
index f3826eb3..40ddffc7 100644
--- a/lib/dir_exist_async.h
+++ b/lib/dir_exist_async.h
@@ -9,7 +9,8 @@
#include <zen/thread.h>
#include <zen/file_handling.h>
-#include "status_handler.h"
+//#include "status_handler.h"
+#include "process_callback.h"
#include <zen/file_error.h>
#include "resolve_path.h"
@@ -20,7 +21,7 @@ bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, Proces
{
using namespace zen;
- procCallback.reportStatus(replaceCpy(_("Searching for directory %x..."), L"%x", std::wstring(L"\"") + dirname + L"\"", false));
+ procCallback.reportStatus(replaceCpy(_("Searching for directory %x..."), L"%x", fmtFileName(dirname), false));
auto ft = async([=]() -> bool
{
diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp
index 87864ce4..402892c6 100644
--- a/lib/dir_lock.cpp
+++ b/lib/dir_lock.cpp
@@ -25,6 +25,8 @@
#include <tlhelp32.h>
#include <zen/win.h> //includes "windows.h"
#include <zen/long_path_prefix.h>
+#include <Sddl.h> //login sid
+#include <Lmcons.h> //UNLEN
#elif defined FFS_LINUX
#include <sys/stat.h>
@@ -37,12 +39,12 @@ using namespace std::rel_ops;
namespace
{
-const size_t EMIT_LIFE_SIGN_INTERVAL = 5000; //show life sign; unit [ms]
-const size_t POLL_LIFE_SIGN_INTERVAL = 6000; //poll for life sign; unit [ms]
-const size_t DETECT_EXITUS_INTERVAL = 30000; //assume abandoned lock; unit [ms]
+const size_t EMIT_LIFE_SIGN_INTERVAL = 5000; //show life sign; unit: [ms]
+const size_t POLL_LIFE_SIGN_INTERVAL = 4000; //poll for life sign; unit: [ms]
+const size_t DETECT_ABANDONED_INTERVAL = 30000; //assume abandoned lock; unit: [ms]
const char LOCK_FORMAT_DESCR[] = "FreeFileSync";
-const int LOCK_FORMAT_VER = 1; //lock file format version
+const int LOCK_FORMAT_VER = 2; //lock file format version
}
//worker thread
@@ -66,7 +68,7 @@ public:
}
catch (const std::exception& e) //exceptions must be catched per thread
{
- wxSafeShowMessage(wxString(_("An exception occurred!")) + wxT("(Dirlock)"), utf8CvrtTo<wxString>(e.what())); //simple wxMessageBox won't do for threads
+ wxSafeShowMessage(_("An exception occurred!") + L" (Dirlock)", utf8CvrtTo<wxString>(e.what())); //simple wxMessageBox won't do for threads
}
}
@@ -97,9 +99,10 @@ public:
return;
DWORD bytesWritten = 0;
+ /*bool rv = */
::WriteFile(fileHandle, //__in HANDLE hFile,
buffer, //__out LPVOID lpBuffer,
- 1, //__in DWORD nNumberOfBytesToRead,
+ 1, //__in DWORD nNumberOfBytesToWrite,
&bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
nullptr); //__inout_opt LPOVERLAPPED lpOverlapped
@@ -129,17 +132,17 @@ UInt64 getLockFileSize(const Zstring& filename) //throw FileError, ErrorNotExist
if (searchHandle != INVALID_HANDLE_VALUE)
{
::FindClose(searchHandle);
- return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
+ return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
}
#elif defined FFS_LINUX
struct ::stat fileInfo = {};
if (::stat(filename.c_str(), &fileInfo) == 0) //follow symbolic links
- return zen::UInt64(fileInfo.st_size);
+ return UInt64(fileInfo.st_size);
#endif
const ErrorCode lastError = getLastError();
- const std::wstring errorMessage = _("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
+ const std::wstring errorMessage = replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted(lastError);
if (errorCodeForNotExisting(lastError))
throw ErrorNotExisting(errorMessage);
@@ -158,73 +161,186 @@ Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT
}
-namespace
+class CheckedLockReader : public CheckedReader
{
-std::string getComputerId() //returns empty string on error
+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
{
- const wxString fhn = ::wxGetFullHostName();
- if (fhn.empty()) return std::string();
+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
- return "Windows " + utf8CvrtTo<std::string>(fhn);
-#elif defined FFS_LINUX
- return "Linux " + utf8CvrtTo<std::string>(fhn);
-#endif
+std::wstring getLoginSid() //throw FileError
+{
+ HANDLE hToken = 0;
+ if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
+ TOKEN_ALL_ACCESS, //__in DWORD DesiredAccess,
+ &hToken)) //__out PHANDLE TokenHandle
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
+
+ DWORD bufferSize = 0;
+ ::GetTokenInformation(hToken, TokenGroups, nullptr, 0, &bufferSize);
+
+ std::vector<char> buffer(bufferSize);
+ if (!::GetTokenInformation(hToken, //__in HANDLE TokenHandle,
+ TokenGroups, //__in TOKEN_INFORMATION_CLASS TokenInformationClass,
+ &buffer[0], //__out_opt LPVOID TokenInformation,
+ bufferSize, //__in DWORD TokenInformationLength,
+ &bufferSize)) //__out PDWORD ReturnLength
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+
+ auto groups = reinterpret_cast<const TOKEN_GROUPS*>(&buffer[0]);
+
+ for (DWORD i = 0; i < groups->GroupCount; ++i)
+ if ((groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0)
+ {
+ LPTSTR sidStr = nullptr;
+ if (!::ConvertSidToStringSid(groups->Groups[i].Sid, //__in PSID Sid,
+ &sidStr)) //__out LPTSTR *StringSid
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ ZEN_ON_SCOPE_EXIT(::LocalFree(sidStr));
+
+ return sidStr;
+ }
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted() + L"(no login found)"); //shouldn't happen
}
+#endif
+
+class FromCurrentProcess {}; //tag
-struct LockInformation
+struct LockInformation //throw FileError
{
- LockInformation()
- {
- lockId = zen::generateGUID();
+ explicit LockInformation(FromCurrentProcess) :
+ lockId(zen::generateGUID()),
#ifdef FFS_WIN
- procDescr.processId = ::GetCurrentProcessId();
-#elif defined FFS_LINUX
- procDescr.processId = ::getpid();
-#endif
- procDescr.computerId = getComputerId();
+ sessionId(utf8CvrtTo<std::string>(getLoginSid())), //throw FileError
+ processId(::GetCurrentProcessId()) //never fails
+ {
+ DWORD bufferSize = 0;
+ ::GetComputerNameEx(ComputerNameDnsFullyQualified, nullptr, &bufferSize); //get required buffer size
+
+ std::vector<wchar_t> buffer(bufferSize);
+ if (!GetComputerNameEx(ComputerNameDnsFullyQualified, //__in COMPUTER_NAME_FORMAT NameType,
+ &buffer[0], //__out LPTSTR lpBuffer,
+ &bufferSize)) //__inout LPDWORD lpnSize
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ computerName = "Windows." + utf8CvrtTo<std::string>(&buffer[0]);
+
+ bufferSize = UNLEN + 1;
+ buffer.resize(bufferSize);
+ if (!::GetUserName(&buffer[0], //__out LPTSTR lpBuffer,
+ &bufferSize)) //__inout LPDWORD lpnSize
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ userId = utf8CvrtTo<std::string>(&buffer[0]);
}
-
- LockInformation(wxInputStream& stream) //read
+#elif defined FFS_LINUX
+ processId(::getpid()) //never fails
{
- char formatDescr[sizeof(LOCK_FORMAT_DESCR)] = {};
- stream.Read(formatDescr, sizeof(LOCK_FORMAT_DESCR)); //file format header
- const int lockFileVersion = readPOD<boost::int32_t>(stream); //
- (void)lockFileVersion;
+ std::vector<char> buffer(10000);
+ if (::gethostname(&buffer[0], buffer.size()) != 0)
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
- //some format checking here?
+ computerName += "Linux."; //distinguish linux/windows lock files
+ computerName += &buffer[0];
- lockId = readString<std::string>(stream);
- procDescr.processId = static_cast<ProcessId>(readPOD<std::uint64_t>(stream)); //possible loss of precision (32/64 bit process) covered by buildId
- procDescr.computerId = readString<std::string>(stream);
+ if (::getdomainname(&buffer[0], buffer.size()) != 0)
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ computerName += ".";
+ computerName += &buffer[0];
+
+ uid_t userIdTmp = ::getuid(); //never fails
+ userId.assign(reinterpret_cast<const char*>(&userIdTmp), sizeof(userIdTmp));
+
+ pid_t sessionIdTmp = ::getsid(0); //new after each restart!
+ if (sessionIdTmp == -1)
+ throw FileError(_("Cannot get process information.") + L"\n\n" + getLastErrorFormatted());
+ sessionId.assign(reinterpret_cast<const char*>(&sessionIdTmp), sizeof(sessionIdTmp));
}
+#endif
- void toStream(wxOutputStream& stream) const //write
+ explicit LockInformation(CheckedLockReader& reader)
{
- assert_static(sizeof(ProcessId) <= sizeof(std::uint64_t)); //ensure portability
+ char tmp[sizeof(LOCK_FORMAT_DESCR)] = {};
+ reader.readArray(&tmp, sizeof(tmp)); //file format header
+ const int lockFileVersion = reader.readPOD<boost::int32_t>(); //
+
+ if (!std::equal(std::begin(tmp), std::end(tmp), std::begin(LOCK_FORMAT_DESCR)) ||
+ lockFileVersion != LOCK_FORMAT_VER)
+ reader.throwException();
+
+ reader.readString(lockId);
+ reader.readString(computerName);
+ reader.readString(userId);
+ reader.readString(sessionId);
+ processId = static_cast<decltype(processId)>(reader.readPOD<std::uint64_t>()); //[!] conversion
+ }
+
+ void toStream(CheckedLockWriter& writer) const
+ {
+ writer.writeArray(LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
+ writer.writePOD<boost::int32_t>(LOCK_FORMAT_VER);
- stream.Write(LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
- writePOD<boost::int32_t>(stream, LOCK_FORMAT_VER);
+ assert_static(sizeof(processId) <= sizeof(std::uint64_t)); //ensure portability
- writeString(stream, lockId);
- writePOD<std::uint64_t>(stream, procDescr.processId);
- writeString(stream, procDescr.computerId);
+ writer.writeString(lockId);
+ writer.writeString(computerName);
+ writer.writeString(userId);
+ writer.writeString(sessionId);
+ writer.writePOD<std::uint64_t>(processId);
}
+ std::string lockId; //16 byte GUID - a universal identifier for this lock (no matter what the path is, considering symlinks, distributed network, etc.)
+
+ std::string computerName; //format: HostName.DomainName
+ std::string userId; //non-readable!
+ std::string sessionId; //
#ifdef FFS_WIN
- typedef DWORD ProcessId; //same size on 32 and 64 bit windows!
+ DWORD processId;
#elif defined FFS_LINUX
- typedef pid_t ProcessId;
+ pid_t processId;
#endif
+};
- std::string lockId; //16 byte UUID
- struct ProcessDescription
- {
- ProcessId processId;
- std::string computerId;
- } procDescr;
-};
+//wxGetFullHostName() is a performance killer for some users, so don't touch!
+
+
+void writeLockInfo(const Zstring& lockfilename) //throw FileError
+{
+ FileOutputStream stream(lockfilename); //throw FileError
+ CheckedLockWriter writer(stream, lockfilename);
+ LockInformation(FromCurrentProcess()).toStream(writer); //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
+}
+
+
+inline
+std::string retrieveLockId(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
+{
+ return retrieveLockInfo(lockfilename).lockId;
+}
//true: process not available, false: cannot say anything
@@ -235,20 +351,24 @@ enum ProcessStatus
PROC_STATUS_ITS_US,
PROC_STATUS_NO_IDEA
};
-ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDescr)
+ProcessStatus getProcessStatus(const LockInformation& lockInfo) //throw FileError
{
- if (procDescr.computerId != getComputerId() ||
- procDescr.computerId.empty()) //both names are empty
- return PROC_STATUS_NO_IDEA; //lock owned by different computer
+ const LockInformation localInfo((FromCurrentProcess())); //throw FileError
-#ifdef FFS_WIN
- if (procDescr.processId == ::GetCurrentProcessId()) //may seem obscure, but it's possible: deletion failed or a lock file is "stolen" and put back while the program is running
+ if (lockInfo.computerName != localInfo.computerName ||
+ lockInfo.userId != localInfo.userId) //another user may run a session right now!
+ return PROC_STATUS_NO_IDEA; //lock owned by different computer in this network
+
+ if (lockInfo.sessionId != localInfo.sessionId)
+ return PROC_STATUS_NOT_RUNNING; //different session but same user? there can be only one
+
+ if (lockInfo.processId == localInfo.processId) //obscure, but possible: deletion failed or a lock file is "stolen" and put back while the program is running
return PROC_STATUS_ITS_US;
- //note: ::OpenProcess() is no option as it may successfully return for crashed processes!
- HANDLE snapshot = ::CreateToolhelp32Snapshot(
- TH32CS_SNAPPROCESS, //__in DWORD dwFlags,
- 0); //__in DWORD th32ProcessID
+#ifdef FFS_WIN
+ //note: ::OpenProcess() is no alternative as it may successfully return for crashed processes! -> remark: "WaitForSingleObject" may identify this case!
+ HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, //__in DWORD dwFlags,
+ 0); //__in DWORD th32ProcessID
if (snapshot == INVALID_HANDLE_VALUE)
return PROC_STATUS_NO_IDEA;
ZEN_ON_SCOPE_EXIT(::CloseHandle(snapshot));
@@ -258,122 +378,104 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
if (!::Process32First(snapshot, //__in HANDLE hSnapshot,
&processEntry)) //__inout LPPROCESSENTRY32 lppe
- return PROC_STATUS_NO_IDEA;
+ return PROC_STATUS_NO_IDEA; //ERROR_NO_MORE_FILES not possible
do
{
- if (processEntry.th32ProcessID == procDescr.processId)
+ if (processEntry.th32ProcessID == lockInfo.processId)
return PROC_STATUS_RUNNING; //process still running
}
while (::Process32Next(snapshot, &processEntry));
+ if (::GetLastError() != ERROR_NO_MORE_FILES) //yes, they call it "files"
+ return PROC_STATUS_NO_IDEA;
return PROC_STATUS_NOT_RUNNING;
#elif defined FFS_LINUX
- if (procDescr.processId == ::getpid()) //may seem obscure, but it's possible: a lock file is "stolen" and put back while the program is running
- return PROC_STATUS_ITS_US;
-
- if (procDescr.processId <= 0 || procDescr.processId >= 65536)
+ if (lockInfo.processId <= 0 || lockInfo.processId >= 65536)
return PROC_STATUS_NO_IDEA; //invalid process id
- return zen::dirExists(Zstr("/proc/") + zen::numberTo<Zstring>(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
+ return zen::dirExists("/proc/" + zen::numberTo<Zstring>(lockInfo.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
#endif
}
-void writeLockInfo(const Zstring& lockfilename) //throw FileError
-{
- //write GUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, distributed network, etc.)
- FileOutputStream lockFile(lockfilename); //throw FileError
- LockInformation().toStream(lockFile);
-}
-
-
-LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
-{
- //read GUID from beginning of file
- FileInputStream lockFile(lockfilename); //throw FileError, ErrorNotExisting
- return LockInformation(lockFile);
-}
-
-
-std::string retrieveLockId(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
-{
- return retrieveLockInfo(lockfilename).lockId;
-}
-}
-
-
void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
{
- const std::wstring infoMsg = replaceCpy(_("Waiting while directory is locked (%x)..."), L"%x", std::wstring(L"\"") + lockfilename + L"\"");
+ const std::wstring infoMsg = replaceCpy(_("Waiting while directory is locked (%x)..."), L"%x", fmtFileName(lockfilename));
if (callback)
callback->reportInfo(infoMsg);
//---------------------------------------------------------------
try
{
- const LockInformation lockInfo = retrieveLockInfo(lockfilename); //throw FileError, ErrorNotExisting
-
- bool lockOwnderDead = false; //convenience optimization: if we know the owning process crashed, we needn't wait DETECT_EXITUS_INTERVAL sec
- switch (getProcessStatus(lockInfo.procDescr))
+ //convenience optimization only: if we know the owning process crashed, we needn't wait DETECT_ABANDONED_INTERVAL sec
+ bool lockOwnderDead = false;
+ std::string originalLockId; //empty if it cannot be retrieved
+ try
{
- case PROC_STATUS_ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process
- case PROC_STATUS_NOT_RUNNING:
- lockOwnderDead = true;
- break;
- case PROC_STATUS_RUNNING:
- case PROC_STATUS_NO_IDEA:
- break;
+ const LockInformation& lockInfo = retrieveLockInfo(lockfilename); //throw FileError, ErrorNotExisting
+ originalLockId = lockInfo.lockId;
+ switch (getProcessStatus(lockInfo)) //throw FileError
+ {
+ case PROC_STATUS_ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process
+ case PROC_STATUS_NOT_RUNNING:
+ lockOwnderDead = true;
+ break;
+ case PROC_STATUS_RUNNING:
+ case PROC_STATUS_NO_IDEA:
+ break;
+ }
}
+ catch (FileError&) {} //logfile may be only partly written -> this is no error!
- zen::UInt64 fileSizeOld;
- wxLongLong lockSilentStart = wxGetLocalTimeMillis();
+ UInt64 fileSizeOld;
+ wxMilliClock_t lastLifeSign = wxGetLocalTimeMillis();
while (true)
{
- const zen::UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError, ErrorNotExisting
- wxLongLong currentTime = wxGetLocalTimeMillis();
+ wxMilliClock_t currentTime = wxGetLocalTimeMillis();
+ const UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError, ErrorNotExisting
if (fileSizeNew != fileSizeOld) //received life sign from lock
{
- fileSizeOld = fileSizeNew;
- lockSilentStart = currentTime;
+ fileSizeOld = fileSizeNew;
+ lastLifeSign = currentTime;
}
if (lockOwnderDead || //no need to wait any longer...
- currentTime - lockSilentStart > DETECT_EXITUS_INTERVAL)
+ currentTime - lastLifeSign > DETECT_ABANDONED_INTERVAL)
{
DirLock dummy(deleteAbandonedLockName(lockfilename), callback); //throw FileError
//now that the lock is in place check existence again: meanwhile another process may have deleted and created a new lock!
- if (retrieveLockId(lockfilename) != lockInfo.lockId) //throw FileError, ErrorNotExisting
- return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over...
+ if (!originalLockId.empty())
+ if (retrieveLockId(lockfilename) != originalLockId) //throw FileError, ErrorNotExisting -> since originalLockId is filled, we are not expecting errors!
+ return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over...
- if (getLockFileSize(lockfilename) != fileSizeOld) //throw FileError, ErrorNotExisting
- continue; //belated lifesign
+ if (::getLockFileSize(lockfilename) != fileSizeOld) //throw FileError, ErrorNotExisting
+ continue; //late life sign
removeFile(lockfilename); //throw FileError
return;
}
//wait some time...
- const size_t GUI_CALLBACK_INTERVAL = 100;
+ assert_static(POLL_LIFE_SIGN_INTERVAL % GUI_CALLBACK_INTERVAL == 0);
for (size_t i = 0; i < POLL_LIFE_SIGN_INTERVAL / GUI_CALLBACK_INTERVAL; ++i)
{
if (callback) callback->requestUiRefresh();
wxMilliSleep(GUI_CALLBACK_INTERVAL);
- //show some countdown on abandoned locks
if (callback)
{
- if (currentTime - lockSilentStart > EMIT_LIFE_SIGN_INTERVAL) //one signal missed: it's likely this is an abandoned lock:
+ //one signal missed: it's likely this is an abandoned lock => show countdown
+ if (currentTime - lastLifeSign > EMIT_LIFE_SIGN_INTERVAL)
{
- long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong();
+ long remainingSeconds = ((DETECT_ABANDONED_INTERVAL - (wxGetLocalTimeMillis() - lastLifeSign)) / 1000).ToLong();
remainingSeconds = std::max(0L, remainingSeconds);
const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", numberTo<std::wstring>(remainingSeconds));
-
callback->reportInfo(infoMsg + L" " + remSecMsg);
}
else
@@ -411,30 +513,32 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
{
- if (::GetLastError() == ERROR_FILE_EXISTS)
+ const DWORD lastError = ::GetLastError();
+ if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
+ lastError == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
return false;
else
- throw FileError(_("Error setting directory lock:") + L"\n\"" + lockfilename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set directory lock %x."), L"%x", fmtFileName(lockfilename)) + L"\n\n" + getLastErrorFormatted());
}
::CloseHandle(fileHandle);
#elif defined FFS_LINUX
//O_EXCL contains a race condition on NFS file systems: http://linux.die.net/man/2/open
- ::umask(0); //important!
+ ::umask(0); //important! -> why?
const int fileHandle = ::open(lockfilename.c_str(), O_CREAT | O_WRONLY | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO);
if (fileHandle == -1)
{
if (errno == EEXIST)
return false;
else
- throw FileError(_("Error setting directory lock:") + L"\n\"" + lockfilename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set directory lock %x."), L"%x", fmtFileName(lockfilename)) + L"\n\n" + getLastErrorFormatted());
}
::close(fileHandle);
#endif
ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilename); });
- //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, etc.)
+ //write housekeeping info: user, process info, lock GUID
writeLockInfo(lockfilename); //throw FileError
guardLockFile.dismiss(); //lockfile created successfully
@@ -485,32 +589,32 @@ public:
//create or retrieve a SharedDirLock
std::shared_ptr<SharedDirLock> retrieve(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
{
- //optimization: check if there is an active(!) lock for "lockfilename"
- FileToUuidMap::const_iterator iterUuid = fileToUuid.find(lockfilename);
- if (iterUuid != fileToUuid.end())
- {
- if (const std::shared_ptr<SharedDirLock>& activeLock = findActive(iterUuid->second)) //returns null-lock if not found
+ tidyUp();
+
+ //optimization: check if we already own a lock for this path
+ auto iterGuid = fileToGuid.find(lockfilename);
+ if (iterGuid != fileToGuid.end())
+ if (const std::shared_ptr<SharedDirLock>& activeLock = getActiveLock(iterGuid->second)) //returns null-lock if not found
return activeLock; //SharedDirLock is still active -> enlarge circle of shared ownership
- }
- try //actual check based on lock UUID, deadlock prevention: "lockfilename" may be an alternative name for an already active lock
+ try //check based on lock GUID, deadlock prevention: "lockfilename" may be an alternative name for a lock already owned by this process
{
const std::string lockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
- if (const std::shared_ptr<SharedDirLock>& activeLock = findActive(lockId)) //returns null-lock if not found
+ if (const std::shared_ptr<SharedDirLock>& activeLock = getActiveLock(lockId)) //returns null-lock if not found
{
- fileToUuid[lockfilename] = lockId; //perf-optimization: update relation
+ fileToGuid[lockfilename] = lockId; //found an alias for one of our active locks
return activeLock;
}
}
- catch (FileError&) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock file
+ catch (FileError&) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock files
- //not yet in buffer, so create a new directory lock
+ //lock not owned by us => create a new one
auto newLock = std::make_shared<SharedDirLock>(lockfilename, callback); //throw FileError
- const std::string& newLockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
+ const std::string& newLockGuid = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
//update registry
- fileToUuid[lockfilename] = newLockId; //throw()
- uuidToLock[newLockId] = newLock; //
+ fileToGuid[lockfilename] = newLockGuid; //throw()
+ guidToLock[newLockGuid] = newLock; //
return newLock;
}
@@ -518,19 +622,24 @@ public:
private:
LockAdmin() {}
- std::shared_ptr<SharedDirLock> findActive(const std::string& lockId) //returns null-lock if not found
+ typedef std::string UniqueId;
+ typedef std::map<Zstring, UniqueId, LessFilename> FileToGuidMap; //n:1 handle uppper/lower case correctly
+ typedef std::map<UniqueId, std::weak_ptr<SharedDirLock>> GuidToLockMap; //1:1
+
+ std::shared_ptr<SharedDirLock> getActiveLock(const UniqueId& lockId) //returns null if none found
{
- auto iterLock = uuidToLock.find(lockId);
- return iterLock != uuidToLock.end() ?
- iterLock->second.lock() : nullptr; //try to get shared_ptr; throw()
+ auto iterLock = guidToLock.find(lockId);
+ return iterLock != guidToLock.end() ? iterLock->second.lock() : nullptr; //try to get shared_ptr; throw()
}
- typedef std::string UniqueId;
- typedef std::map<Zstring, UniqueId, LessFilename> FileToUuidMap; //n:1 handle uppper/lower case correctly
- typedef std::map<UniqueId, std::weak_ptr<SharedDirLock>> UuidToLockMap; //1:1
+ void tidyUp() //remove obsolete lock entries
+ {
+ map_remove_if(guidToLock, [ ](const GuidToLockMap::value_type& v) { return !v.second.lock(); });
+ map_remove_if(fileToGuid, [&](const FileToGuidMap::value_type& v) { return guidToLock.find(v.second) == guidToLock.end(); });
+ }
- FileToUuidMap fileToUuid; //lockname |-> UUID; locks can be referenced by a lockfilename or alternatively a UUID
- UuidToLockMap uuidToLock; //UUID |-> "shared lock ownership"
+ FileToGuidMap fileToGuid; //lockname |-> GUID; locks can be referenced by a lockfilename or alternatively a GUID
+ GuidToLockMap guidToLock; //GUID |-> "shared lock ownership"
};
@@ -549,5 +658,5 @@ DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw
}
#endif
- sharedLock = LockAdmin::instance().retrieve(lockfilename, callback);
+ sharedLock = LockAdmin::instance().retrieve(lockfilename, callback); //throw FileError
}
diff --git a/lib/dir_lock.h b/lib/dir_lock.h
index 3e9f2a79..925d99d6 100644
--- a/lib/dir_lock.h
+++ b/lib/dir_lock.h
@@ -9,6 +9,9 @@
#include <memory>
#include <zen/file_error.h>
+namespace zen
+{
+const size_t GUI_CALLBACK_INTERVAL = 100;
struct DirLockCallback //while waiting for the lock
{
@@ -20,12 +23,12 @@ struct DirLockCallback //while waiting for the lock
/*
RAII structure to place a directory lock against other FFS processes:
- recursive locking supported, even with alternate lockfile names, e.g. via symlinks, network mounts etc.
- - ownership shared between all object instances refering to a specific lock location(= UUID)
+ - ownership shared between all object instances refering to a specific lock location(= GUID)
- can be copied safely and efficiently! (ref-counting)
- detects and resolves abandoned locks (instantly if lock is associated with local pc, else after 30 seconds)
- temporary locks created during abandoned lock resolution keep "lockfilename"'s extension
- race-free (Windows, almost on Linux(NFS))
- - currently NOT thread-safe! (static LockAdmin)
+ - NOT thread-safe! (1. static LockAdmin 2. directory name aliases must be resolved sequentially!)
*/
class DirLock
{
@@ -37,5 +40,6 @@ private:
class SharedDirLock;
std::shared_ptr<SharedDirLock> sharedLock;
};
+}
#endif // DIR_LOCK_H_INCLUDED
diff --git a/lib/ffs_paths.h b/lib/ffs_paths.h
index ac032e6b..9376825b 100644
--- a/lib/ffs_paths.h
+++ b/lib/ffs_paths.h
@@ -79,14 +79,7 @@ Zstring getResourceDir()
if (isPortableVersion())
return impl::getBinaryDir();
else //use OS' standard paths
- {
- Zstring resourceDir = toZ(wxStandardPathsBase::Get().GetResourcesDir());
-
- if (!endsWith(resourceDir, FILE_NAME_SEPARATOR))
- resourceDir += FILE_NAME_SEPARATOR;
-
- return resourceDir;
- }
+ return appendSeparator(toZ(wxStandardPathsBase::Get().GetResourcesDir()));
#endif
}
@@ -113,10 +106,7 @@ Zstring getConfigDir()
}
catch (const FileError&) {}
- if (!endsWith(userDirectory, FILE_NAME_SEPARATOR))
- userDirectory += FILE_NAME_SEPARATOR;
-
- return userDirectory;
+ return appendSeparator(userDirectory);
}
}
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
index e1518d30..daf32a86 100644
--- a/lib/icon_buffer.cpp
+++ b/lib/icon_buffer.cpp
@@ -9,7 +9,7 @@
#include <set>
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
-#include <boost/thread/once.hpp>
+//#include <boost/thread/once.hpp>
#ifdef FFS_WIN
#include <zen/dll.h>
@@ -147,7 +147,7 @@ Zstring getFileExtension(const Zstring& filename)
{
const Zstring shortName = afterLast(filename, Zchar('\\')); //warning: using windows file name separator!
- return shortName.find(Zchar('.')) != Zstring::npos ?
+ return contains(shortName, Zchar('.')) ?
afterLast(filename, Zchar('.')) :
Zstring();
}
@@ -193,7 +193,7 @@ int getShilIconType(IconBuffer::IconSize sz)
}
-DllFun<thumb::GetIconByIndexFct> getIconByIndex;
+DllFun<thumb::FunType_getIconByIndex> getIconByIndex;
boost::once_flag initGetIconByIndexOnce = BOOST_ONCE_INIT;
@@ -210,9 +210,10 @@ IconHolder getIconByAttribute(LPCWSTR pszPath, DWORD dwFileAttributes, IconBuffe
if (!imgList)
return IconHolder();
- boost::call_once(initGetIconByIndexOnce, []() //thread-safe init
+ boost::call_once(initGetIconByIndexOnce, [] //thread-safe init
{
- getIconByIndex = DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
+ using namespace thumb;
+ getIconByIndex = DllFun<FunType_getIconByIndex>(getDllName(), funName_getIconByIndex);
});
return IconHolder(getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : nullptr);
}
@@ -221,11 +222,11 @@ IconHolder getIconByAttribute(LPCWSTR pszPath, DWORD dwFileAttributes, IconBuffe
IconHolder getAssociatedIconByExt(const Zstring& extension, IconBuffer::IconSize sz)
{
//no read-access to disk! determine icon by extension
- return getIconByAttribute((Zstr("dummy.") + extension).c_str(), FILE_ATTRIBUTE_NORMAL, sz);
+ return getIconByAttribute((L"dummy." + extension).c_str(), FILE_ATTRIBUTE_NORMAL, sz);
}
-DllFun<thumb::GetThumbnailFct> getThumbnailIcon;
+DllFun<thumb::FunType_getThumbnail> getThumbnailIcon;
boost::once_flag initThumbnailOnce = BOOST_ONCE_INIT;
#endif
}
@@ -235,11 +236,10 @@ boost::once_flag initThumbnailOnce = BOOST_ONCE_INIT;
IconHolder getThumbnail(const Zstring& filename, int requestedSize) //return 0 on failure
{
#ifdef FFS_WIN
- using namespace thumb;
-
- boost::call_once(initThumbnailOnce, []() //note: "getThumbnail" function itself is already thread-safe
+ boost::call_once(initThumbnailOnce, [] //note: "getThumbnail" function itself is already thread-safe
{
- getThumbnailIcon = DllFun<GetThumbnailFct>(getDllName(), getThumbnailFctName);
+ using namespace thumb;
+ getThumbnailIcon = DllFun<FunType_getThumbnail>(getDllName(), funName_getThumbnail);
});
return IconHolder(getThumbnailIcon ? static_cast< ::HICON>(getThumbnailIcon(filename.c_str(), requestedSize)) : nullptr);
@@ -253,6 +253,7 @@ IconHolder getThumbnail(const Zstring& filename, int requestedSize) //return 0 o
const char* mimeFileIcons[] =
{
"application-x-zerosize", //Kubuntu: /usr/share/icons/oxygen/48x48/mimetypes
+ "text-x-generic", //http://live.gnome.org/GnomeArt/Tutorials/IconThemes
"empty", //
"gtk-file", //Ubuntu: /usr/share/icons/Humanity/mimes/48
"gnome-fs-regular", //
@@ -320,7 +321,7 @@ IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
boost::call_once(initGetIconByIndexOnce, [] //thread-safe init
{
- getIconByIndex = DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
+ getIconByIndex = DllFun<thumb::FunType_getIconByIndex>(thumb::getDllName(), thumb::funName_getIconByIndex);
});
return IconHolder(getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : nullptr);
@@ -382,7 +383,7 @@ public:
boost::unique_lock<boost::mutex> dummy(lockFiles);
while (filesToLoad.empty())
- conditionNewFiles.timed_wait(dummy, boost::get_system_time() + boost::posix_time::milliseconds(50)); //interruption point!
+ conditionNewFiles.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point!
Zstring fileName = filesToLoad.back();
filesToLoad.pop_back();
diff --git a/lib/localization.cpp b/lib/localization.cpp
index 3c997074..f056aea0 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -284,11 +284,16 @@ wxLanguage mapLanguageDialect(wxLanguage language)
case wxLANGUAGE_SWEDISH_FINLAND:
return wxLANGUAGE_SWEDISH;
+ //variants of wxLANGUAGE_NORWEGIAN_BOKMAL
+ case wxLANGUAGE_NORWEGIAN_NYNORSK:
+ return wxLANGUAGE_NORWEGIAN_BOKMAL;
+
//case wxLANGUAGE_CZECH:
//case wxLANGUAGE_DANISH:
//case wxLANGUAGE_FINNISH:
//case wxLANGUAGE_GREEK:
//case wxLANGUAGE_JAPANESE:
+ //case wxLANGUAGE_LITHUANIAN:
//case wxLANGUAGE_POLISH:
//case wxLANGUAGE_SLOVENIAN:
//case wxLANGUAGE_HUNGARIAN:
@@ -384,22 +389,21 @@ void zen::setLanguage(int language)
//load language file into buffer
if (!languageFile.empty()) //if languageFile is empty texts will be english per default
- {
try
{
zen::setTranslator(new FFSLocale(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, PluralForm::ParsingError
}
catch (lngfile::ParsingError& e)
{
- wxMessageBox(wxString(_("Error reading file:")) + wxT(" \"") + languageFile + wxT("\"") + wxT("\n\n") +
- wxT("Row: ") + zen::toStringSep(e.row) + wxT("\n") +
- wxT("Column: ") + zen::toStringSep(e.col) + wxT("\n"), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
+ L"%x", fmtFileName(toZ(languageFile))),
+ L"%y", numberTo<std::wstring>(e.row)),
+ L"%z", numberTo<std::wstring>(e.col)), _("Error"), wxOK | wxICON_ERROR);
}
catch (PluralForm::ParsingError&)
{
- wxMessageBox(wxT("Invalid Plural Form"), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(L"Invalid Plural Form", _("Error"), wxOK | wxICON_ERROR);
}
- }
}
diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp
index 6c9fd3ee..9ab99920 100644
--- a/lib/parallel_scan.cpp
+++ b/lib/parallel_scan.cpp
@@ -85,7 +85,7 @@ DiskInfo retrieveDiskInfo(const Zstring& pathName)
HANDLE hVolume = ::CreateFile(volnameFmt.c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
- 0,
+ nullptr,
OPEN_EXISTING,
0,
nullptr);
@@ -237,12 +237,12 @@ public:
std::wstring getCurrentStatus() //context of main thread, call repreatedly
{
- std::wstring filename;
+ Zstring filename;
std::wstring statusMsg;
{
boost::lock_guard<boost::mutex> dummy(lockCurrentStatus);
if (!currentFile.empty())
- filename = utf8CvrtTo<std::wstring>(currentFile);
+ filename = currentFile;
else if (!currentStatus.empty())
statusMsg = copyStringTo<std::wstring>(currentStatus);
}
@@ -252,11 +252,9 @@ public:
std::wstring statusText = copyStringTo<std::wstring>(textScanning);
const long activeCount = activeWorker;
if (activeCount >= 2)
- {
- statusText += L" " + _P("[1 Thread]", "[%x Threads]", activeCount);
- replace(statusText, L"%x", numberTo<std::wstring>(activeCount));
- }
- statusText += std::wstring(L" \n") + L'\"' + filename + L'\"';
+ statusText += L" " + replaceCpy(_P("[1 Thread]", "[%x Threads]", activeCount), L"%x", numberTo<std::wstring>(activeCount));
+
+ statusText += L" " + fmtFileName(filename);
return statusText;
}
else
@@ -451,18 +449,17 @@ public:
DstHackCallbackImpl(AsyncCallback& acb, int threadID) :
acb_(acb),
threadID_(threadID),
- textApplyingDstHack(toZ(replaceCpy(_("Encoding extended time information: %x"), L"%x", L"\n\"%x\""))) {}
+ textApplyingDstHack(replaceCpy(_("Encoding extended time information: %x"), L"%x", L"\n%x")) {}
private:
virtual void requestUiRefresh(const Zstring& filename) //applying DST hack imposes significant one-time performance drawback => callback to inform user
{
- const Zstring statusText = replaceCpy(textApplyingDstHack, Zstr("%x"), filename);
- acb_.reportCurrentStatus(utf8CvrtTo<std::wstring>(statusText), threadID_);
+ acb_.reportCurrentStatus(replaceCpy(textApplyingDstHack, L"%x", fmtFileName(filename)), threadID_);
}
AsyncCallback& acb_;
int threadID_;
- const Zstring textApplyingDstHack;
+ const std::wstring textApplyingDstHack;
};
#endif
//------------------------------------------------------------------------------------------
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index 3c5820d0..141266b6 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -82,7 +82,7 @@ struct BinaryExp : public Expr<typename StlOp::result_type>
template <class StlOp>
inline
-BinaryExp<StlOp> makeBiExp(const Expression& lhs, const Expression& rhs, StlOp biop) //throw (std::bad_cast)
+BinaryExp<StlOp> makeBiExp(const Expression& lhs, const Expression& rhs, StlOp biop) //throw std::bad_cast
{
return BinaryExp<StlOp>(dynamic_cast<const Expr<typename StlOp::first_argument_type >&>(lhs),
dynamic_cast<const Expr<typename StlOp::second_argument_type>&>(rhs), biop);
diff --git a/lib/statistics.cpp b/lib/perf_check.cpp
index 7b3bceae..897be12c 100644
--- a/lib/statistics.cpp
+++ b/lib/perf_check.cpp
@@ -4,104 +4,72 @@
// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#include "statistics.h"
+#include "perf_check.h"
#include <limits>
-#include <wx/ffile.h>
-#include <wx/stopwatch.h>
+//#include <wx/ffile.h>
#include <zen/basic_math.h>
-#include <zen/assert_static.h>
#include <zen/i18n.h>
#include <wx+/format_unit.h>
-
using namespace zen;
-RetrieveStatistics::~RetrieveStatistics()
+PerfCheck::PerfCheck(unsigned windowSizeRemainingTime,
+ unsigned windowSizeBytesPerSecond) :
+ windowSizeRemTime(windowSizeRemainingTime),
+ windowSizeBPS(windowSizeBytesPerSecond),
+ windowMax(std::max(windowSizeRemainingTime, windowSizeBytesPerSecond)) {}
+
+
+PerfCheck::~PerfCheck()
{
- //write statistics to a file
+ /*
+ //write samples to a file
wxFFile outputFile(wxT("statistics.dat"), wxT("w"));
outputFile.Write(wxT("Time(ms);Objects;Data\n"));
- std::for_each(data.begin(), data.end(),
- [&](const StatEntry& entry)
+ for (auto iter = samples.begin(); iter != samples.end(); ++iter)
{
- outputFile.Write(numberTo<wxString>(entry.time));
+ outputFile.Write(numberTo<wxString>(iter->first));
outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(entry.objects));
+ outputFile.Write(numberTo<wxString>(iter->second.objCount_));
outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(entry.value));
+ outputFile.Write(numberTo<wxString>(iter->second.data_));
outputFile.Write(wxT("\n"));
- });
-}
-
-
-void RetrieveStatistics::writeEntry(double value, int objects)
-{
- StatEntry newEntry;
- newEntry.value = value;
- newEntry.objects = objects;
- newEntry.time = timer.Time();
- data.push_back(newEntry);
+ }
+ */
}
-//########################################################################################
-Statistics::Statistics(int totalObjectCount,
- double totalDataAmount,
- unsigned windowSizeRemainingTime,
- unsigned windowSizeBytesPerSecond) :
- objectsTotal(totalObjectCount),
- dataTotal(totalDataAmount),
- windowSizeRemTime(windowSizeRemainingTime),
- windowSizeBPS(windowSizeBytesPerSecond),
- windowMax(std::max(windowSizeRemainingTime, windowSizeBytesPerSecond)) {}
-
-
-void Statistics::addMeasurement(int objectsCurrent, double dataCurrent)
+void PerfCheck::addSample(int objectsCurrent, double dataCurrent, long timeMs)
{
- Record newRecord;
- newRecord.objects = objectsCurrent;
- newRecord.data = dataCurrent;
-
- const long now = timer.Time();
-
- measurements.insert(measurements.end(), std::make_pair(now, newRecord)); //use fact that time is monotonously ascending
+ samples.insert(samples.end(), std::make_pair(timeMs, Record(objectsCurrent, dataCurrent))); //use fact that time is monotonously ascending
//remove all records earlier than "now - windowMax"
- const long newBegin = now - windowMax;
- TimeRecordMap::iterator windowBegin = measurements.upper_bound(newBegin);
- if (windowBegin != measurements.begin())
- measurements.erase(measurements.begin(), --windowBegin); //retain one point before newBegin in order to handle "measurement holes"
+ const long newBegin = timeMs - windowMax;
+ auto iterWindowBegin = samples.upper_bound(newBegin);
+ if (iterWindowBegin != samples.begin())
+ samples.erase(samples.begin(), --iterWindowBegin); //keep one point before newBegin in order to handle "measurement holes"
}
-void Statistics::setNewTotal(int totalObjectCount, double totalDataAmount)
+wxString PerfCheck::getRemainingTime(double dataRemaining) const
{
- objectsTotal = totalObjectCount;
- dataTotal = totalDataAmount;
-}
-
-
-wxString Statistics::getRemainingTime() const
-{
- if (!measurements.empty())
+ if (!samples.empty())
{
- const TimeRecordMap::value_type& backRecord = *measurements.rbegin();
+ const auto& recordBack = *samples.rbegin();
//find start of records "window"
- const long frontTime = backRecord.first - windowSizeRemTime;
- TimeRecordMap::const_iterator windowBegin = measurements.upper_bound(frontTime);
- if (windowBegin != measurements.begin())
- --windowBegin; //one point before window begin in order to handle "measurement holes"
+ auto iterFront = samples.upper_bound(recordBack.first - windowSizeRemTime);
+ if (iterFront != samples.begin())
+ --iterFront; //one point before window begin in order to handle "measurement holes"
- const TimeRecordMap::value_type& frontRecord = *windowBegin;
+ const auto& recordFront = *iterFront;
//-----------------------------------------------------------------------------------------------
- const double timeDelta = backRecord.first - frontRecord.first;
- const double dataDelta = backRecord.second.data - frontRecord.second.data;
+ const double timeDelta = recordBack.first - recordFront.first;
+ const double dataDelta = recordBack.second.data_ - recordFront.second.data_;
- const double dataRemaining = dataTotal - backRecord.second.data;
//objects do *NOT* correspond to disk accesses, so we better play safe and use "bytes" only!
//https://sourceforge.net/tracker/index.php?func=detail&aid=3452469&group_id=234430&atid=1093083
@@ -111,47 +79,51 @@ wxString Statistics::getRemainingTime() const
return zen::remainingTimeToShortString(remTimeSec);
}
}
-
return wxT("-"); //fallback
}
-wxString Statistics::getBytesPerSecond() const
+wxString PerfCheck::getBytesPerSecond() const
{
- if (!measurements.empty())
+ if (!samples.empty())
{
- const TimeRecordMap::value_type& backRecord = *measurements.rbegin();
+ const auto& recordBack = *samples.rbegin();
//find start of records "window"
- const long frontTime = backRecord.first - windowSizeBPS;
- TimeRecordMap::const_iterator windowBegin = measurements.upper_bound(frontTime);
- if (windowBegin != measurements.begin())
- --windowBegin; //one point before window begin in order to handle "measurement holes"
+ auto iterFront = samples.upper_bound(recordBack.first - windowSizeBPS);
+ if (iterFront != samples.begin())
+ --iterFront; //one point before window begin in order to handle "measurement holes"
- const TimeRecordMap::value_type& frontRecord = *windowBegin;
+ const auto& recordFront = *iterFront;
//-----------------------------------------------------------------------------------------------
- const double timeDelta = backRecord.first - frontRecord.first;
- const double dataDelta = backRecord.second.data - frontRecord.second.data;
+ const double timeDelta = recordBack.first - recordFront.first;
+ const double dataDelta = recordBack.second.data_ - recordFront.second.data_;
if (!numeric::isNull(timeDelta))
if (dataDelta > 0) //may be negative if user cancels copying
return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
}
-
return wxT("-"); //fallback
}
-void Statistics::pauseTimer()
+wxString PerfCheck::getOverallBytesPerSecond() const //for all samples
{
- timer.Pause();
-}
-
+ if (!samples.empty())
+ {
+ const auto& recordBack = *samples.rbegin();
+ const auto& recordFront = *samples.begin();
+ //-----------------------------------------------------------------------------------------------
+ const double timeDelta = recordBack.first - recordFront.first;
+ const double dataDelta = recordBack.second.data_ - recordFront.second.data_;
-void Statistics::resumeTimer()
-{
- timer.Resume();
+ if (!numeric::isNull(timeDelta))
+ if (dataDelta > 0) //may be negative if user cancels copying
+ return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
+ }
+ return wxT("-"); //fallback
}
+
/*
class for calculation of remaining time:
----------------------------------------
diff --git a/lib/perf_check.h b/lib/perf_check.h
new file mode 100644
index 00000000..b0d4db89
--- /dev/null
+++ b/lib/perf_check.h
@@ -0,0 +1,40 @@
+// **************************************************************************
+// * 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 STATISTICS_H_INCLUDED
+#define STATISTICS_H_INCLUDED
+
+#include <map>
+#include <wx/string.h>
+
+class PerfCheck
+{
+public:
+ PerfCheck(unsigned windowSizeRemainingTime, //unit: [ms]
+ unsigned windowSizeBytesPerSecond); //
+ ~PerfCheck();
+
+ void addSample(int objectsCurrent, double dataCurrent, long timeMs); //timeMs must be ascending!
+
+ wxString getRemainingTime(double dataRemaining) const;
+ wxString getBytesPerSecond() const; //for window
+ wxString getOverallBytesPerSecond() const; //for all samples
+
+private:
+ const long windowSizeRemTime; //unit: [ms]
+ const long windowSizeBPS; //
+ const long windowMax;
+
+ struct Record
+ {
+ Record(int objCount, double data) : objCount_(objCount), data_(data) {}
+ int objCount_;
+ double data_; //unit: [bytes]
+ };
+ std::multimap<long, Record> samples; ////time, unit: [ms]
+};
+
+#endif // STATISTICS_H_INCLUDED
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index 7fc7b066..a3ed5bfc 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -35,13 +35,13 @@ XmlType getXmlType(const zen::XmlDoc& doc) //throw()
}
-XmlType xmlAccess::getXmlType(const wxString& filename) //throw()
+XmlType xmlAccess::getXmlType(const Zstring& filename) //throw()
{
XmlDoc doc;
try
{
//do NOT use zen::loadStream as it will superfluously load even huge files!
- loadXmlDocument(toZ(filename), doc); //throw FfsXmlError, quick exit if file is not an FFS XML
+ loadXmlDocument(filename, doc); //throw FfsXmlError, quick exit if file is not an FFS XML
}
catch (const FfsXmlError&)
{
@@ -110,7 +110,7 @@ xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchCo
}
-xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg, const wxString& referenceFile)
+xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg, const Zstring& referenceFile)
{
//try to take over batch-specific settings from reference
if (!referenceFile.empty() && getXmlType(referenceFile) == XML_TYPE_BATCH)
@@ -118,7 +118,7 @@ xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiCo
{
XmlBatchConfig output;
- std::vector<wxString> filenames;
+ std::vector<Zstring> filenames;
filenames.push_back(referenceFile);
convertConfig(filenames, output); //throw xmlAccess::FfsXmlError
@@ -144,7 +144,7 @@ xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiCo
}
-xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filenames) //throw ()
+xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<Zstring>& filenames) //throw()
{
bool guiCfgExists = false;
bool batchCfgExists = false;
@@ -181,7 +181,7 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filena
namespace
{
template <class XmlCfg>
-XmlCfg loadCfgImpl(const wxString& filename, std::unique_ptr<xmlAccess::FfsXmlError>& exeption) //throw xmlAccess::FfsXmlError
+XmlCfg loadCfgImpl(const Zstring& filename, std::unique_ptr<xmlAccess::FfsXmlError>& exeption) //throw xmlAccess::FfsXmlError
{
XmlCfg cfg;
try
@@ -200,7 +200,7 @@ XmlCfg loadCfgImpl(const wxString& filename, std::unique_ptr<xmlAccess::FfsXmlEr
template <class XmlCfg>
-void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config) //throw xmlAccess::FfsXmlError
+void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config) //throw xmlAccess::FfsXmlError
{
assert(!filenames.empty());
if (filenames.empty())
@@ -208,9 +208,10 @@ void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config
std::vector<zen::MainConfiguration> mainCfgs;
std::unique_ptr<FfsXmlError> savedException;
+ Zstring invalidFile;
std::for_each(filenames.begin(), filenames.end(),
- [&](const wxString& filename)
+ [&](const Zstring& filename)
{
switch (getXmlType(filename))
{
@@ -224,12 +225,13 @@ void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config
case XML_TYPE_GLOBAL:
case XML_TYPE_OTHER:
+ invalidFile = filename;
break;
}
});
if (mainCfgs.empty())
- throw FfsXmlError(_("Invalid FreeFileSync config file!"));
+ 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
{
@@ -245,15 +247,15 @@ void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config
}
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config) //throw (xmlAccess::FfsXmlError)
+void xmlAccess::convertConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config) //throw FfsXmlError
{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
+ mergeConfigFilesImpl(filenames, config); //throw FfsXmlError
}
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config) //throw (xmlAccess::FfsXmlError);
+void xmlAccess::convertConfig(const std::vector<Zstring>& filenames, XmlBatchConfig& config) //throw FfsXmlError
{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
+ mergeConfigFilesImpl(filenames, config); //throw FfsXmlError
}
@@ -838,7 +840,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inShared["CopyLockedFiles" ](config.copyLockedFiles);
inShared["CopyFilePermissions" ](config.copyFilePermissions);
inShared["TransactionalFileCopy"](config.transactionalFileCopy);
- inShared["VerifyCopiedFiles" ](config.verifyFileCopy);
+ inShared["LockDirectoriesDuringSync"](config.createLockFile);
+ inShared["VerifyCopiedFiles" ](config.verifyFileCopy);
inShared["RunWithBackgroundPriority"](config.runWithBackgroundPriority);
//max. allowed file time deviation
@@ -866,28 +869,30 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inWnd.attribute("PosY", config.gui.dlgPos.y);
inWnd.attribute("Maximized", config.gui.isMaximized);
- inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
-
- inWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
- inWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
- inWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
+ XmlIn inManualDel = inWnd["ManualDeletion"];
+ inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ inManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
- inWnd["ShowIcons"](config.gui.showIcons);
- inWnd["IconSize"](config.gui.iconSize);
+ inWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
+ inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
//###########################################################
//read column attributes
- XmlIn inColNavi = inWnd["CompressedView"];
+ XmlIn inColNavi = inWnd["OverviewColumns"];
inColNavi(config.gui.columnAttribNavi);
inColNavi.attribute("ShowPercentage", config.gui.showPercentBar);
inColNavi.attribute("SortByColumn", config.gui.naviLastSortColumn);
inColNavi.attribute("SortAscending", config.gui.naviLastSortAscending);
- XmlIn inColLeft = inWnd["ColumnsLeft"];
+ XmlIn inMainGrid = inWnd["MainGrid"];
+ inMainGrid.attribute("ShowIcons", config.gui.showIcons);
+ inMainGrid.attribute("IconSize", config.gui.iconSize);
+
+ XmlIn inColLeft = inMainGrid["ColumnsLeft"];
inColLeft(config.gui.columnAttribLeft);
- XmlIn inColRight = inWnd["ColumnsRight"];
+ XmlIn inColRight = inMainGrid["ColumnsRight"];
inColRight(config.gui.columnAttribRight);
//###########################################################
@@ -922,27 +927,27 @@ void readConfig(const Zstring& filename, XmlType type, ConfigType& config)
loadXmlDocument(filename, doc); //throw FfsXmlError
if (getXmlType(doc) != type) //throw()
- throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + filename + L"\"");
+ throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
XmlIn in(doc);
::readConfig(in, config);
if (in.errorsOccured())
- throw FfsXmlError(_("Configuration loaded partially only:") + L"\n\"" + filename + L"\"\n\n" +
+ throw FfsXmlError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" +
getErrorMessageFormatted(in), FfsXmlError::WARNING);
}
}
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
+void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlGuiConfig& config)
{
- ::readConfig(toZ(filename), XML_TYPE_GUI, config);
+ ::readConfig(filename, XML_TYPE_GUI, config);
}
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlBatchConfig& config)
+void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlBatchConfig& config)
{
- ::readConfig(toZ(filename), XML_TYPE_BATCH, config);
+ ::readConfig(filename, XML_TYPE_BATCH, config);
}
@@ -1104,7 +1109,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outShared["CopyLockedFiles" ](config.copyLockedFiles);
outShared["CopyFilePermissions" ](config.copyFilePermissions);
outShared["TransactionalFileCopy"](config.transactionalFileCopy);
- outShared["VerifyCopiedFiles" ](config.verifyFileCopy);
+ outShared["LockDirectoriesDuringSync"](config.createLockFile);
+ outShared["VerifyCopiedFiles" ](config.verifyFileCopy);
outShared["RunWithBackgroundPriority"](config.runWithBackgroundPriority);
//max. allowed file time deviation
@@ -1132,28 +1138,30 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outWnd.attribute("PosY", config.gui.dlgPos.y);
outWnd.attribute("Maximized", config.gui.isMaximized);
- outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
-
- outWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
- outWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
- outWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
+ XmlOut outManualDel = outWnd["ManualDeletion"];
+ outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ outManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
- outWnd["ShowIcons"](config.gui.showIcons);
- outWnd["IconSize"](config.gui.iconSize);
+ outWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
+ outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
//###########################################################
//write column attributes
- XmlOut outColNavi = outWnd["CompressedView"];
+ XmlOut outColNavi = outWnd["OverviewColumns"];
outColNavi(config.gui.columnAttribNavi);
outColNavi.attribute("ShowPercentage", config.gui.showPercentBar);
outColNavi.attribute("SortByColumn", config.gui.naviLastSortColumn);
outColNavi.attribute("SortAscending", config.gui.naviLastSortAscending);
- XmlOut outColLeft = outWnd["ColumnsLeft"];
+ XmlOut outMainGrid = outWnd["MainGrid"];
+ outMainGrid.attribute("ShowIcons", config.gui.showIcons);
+ outMainGrid.attribute("IconSize", config.gui.iconSize);
+
+ XmlOut outColLeft = outMainGrid["ColumnsLeft"];
outColLeft(config.gui.columnAttribLeft);
- XmlOut outColRight = outWnd["ColumnsRight"];
+ XmlOut outColRight = outMainGrid["ColumnsRight"];
outColRight(config.gui.columnAttribRight);
//###########################################################
@@ -1182,7 +1190,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
template <class ConfigType>
-void writeConfig(const ConfigType& config, XmlType type, const wxString& filename)
+void writeConfig(const ConfigType& config, XmlType type, const Zstring& filename)
{
XmlDoc doc("FreeFileSync");
setXmlType(doc, type); //throw()
@@ -1190,17 +1198,17 @@ void writeConfig(const ConfigType& config, XmlType type, const wxString& filenam
XmlOut out(doc);
writeConfig(config, out);
- saveXmlDocument(doc, toZ(filename)); //throw FfsXmlError
+ saveXmlDocument(doc, filename); //throw FfsXmlError
}
}
-void xmlAccess::writeConfig(const XmlGuiConfig& config, const wxString& filename)
+void xmlAccess::writeConfig(const XmlGuiConfig& config, const Zstring& filename)
{
::writeConfig(config, XML_TYPE_GUI, filename); //throw FfsXmlError
}
-void xmlAccess::writeConfig(const XmlBatchConfig& config, const wxString& filename)
+void xmlAccess::writeConfig(const XmlBatchConfig& config, const Zstring& filename)
{
::writeConfig(config, XML_TYPE_BATCH, filename); //throw FfsXmlError
}
@@ -1208,13 +1216,13 @@ void xmlAccess::writeConfig(const XmlBatchConfig& config, const wxString& filena
void xmlAccess::writeConfig(const XmlGlobalSettings& config)
{
- ::writeConfig(config, XML_TYPE_GLOBAL, getGlobalConfigFile()); //throw FfsXmlError
+ ::writeConfig(config, XML_TYPE_GLOBAL, toZ(getGlobalConfigFile())); //throw FfsXmlError
}
wxString xmlAccess::extractJobName(const wxString& configFilename)
{
- const wxString shortName = configFilename.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if seperator not found
- const wxString jobName = shortName.BeforeLast(wxChar('.')); //returns empty string if seperator not found
+ const wxString shortName = afterLast(configFilename, utf8CvrtTo<wxString>(FILE_NAME_SEPARATOR)); //returns the whole string if separator not found
+ const wxString jobName = beforeLast(shortName, L'.'); //returns empty string if seperator not found
return jobName.IsEmpty() ? shortName : jobName;
}
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 801deede..767e4a40 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -23,7 +23,7 @@ enum XmlType
XML_TYPE_OTHER
};
-XmlType getXmlType(const wxString& filename); //throw()
+XmlType getXmlType(const Zstring& filename); //throw()
enum OnError
@@ -124,7 +124,8 @@ struct XmlGlobalSettings
runWithBackgroundPriority(false),
fileTimeTolerance(2), //default 2s: FAT vs NTFS
verifyFileCopy(false),
- transactionalFileCopy(true) {}
+ transactionalFileCopy(true),
+ createLockFile(true) {}
int programLanguage;
bool copyLockedFiles; //VSS usage
@@ -135,6 +136,7 @@ struct XmlGlobalSettings
size_t fileTimeTolerance; //max. allowed file time deviation
bool verifyFileCopy; //verify copied files
bool transactionalFileCopy;
+ bool createLockFile;
OptionalDialogs optDialogs;
@@ -222,17 +224,17 @@ struct XmlGlobalSettings
//struct Batch
};
-void readConfig(const wxString& filename, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
-void readConfig(const wxString& filename, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
-void readConfig( XmlGlobalSettings& config); //throw xmlAccess::FfsXmlError
+void readConfig(const Zstring& filename, XmlGuiConfig& config); //throw FfsXmlError
+void readConfig(const Zstring& filename, XmlBatchConfig& config); //throw FfsXmlError
+void readConfig( XmlGlobalSettings& config); //throw FfsXmlError
-void writeConfig(const XmlGuiConfig& config, const wxString& filename); //throw xmlAccess::FfsXmlError
-void writeConfig(const XmlBatchConfig& config, const wxString& filename); //throw xmlAccess::FfsXmlError
-void writeConfig(const XmlGlobalSettings& config); //throw xmlAccess::FfsXmlError
+void writeConfig(const XmlGuiConfig& config, const Zstring& filename); //throw FfsXmlError
+void writeConfig(const XmlBatchConfig& config, const Zstring& filename); //throw FfsXmlError
+void writeConfig(const XmlGlobalSettings& config); //throw FfsXmlError
//config conversion utilities
XmlGuiConfig convertBatchToGui(const XmlBatchConfig& batchCfg);
-XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg, const wxString& referenceFile);
+XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg, const Zstring& referenceFile);
//convert (multiple) *.ffs_gui, *.ffs_batch files or combinations of both into target config structure:
@@ -243,10 +245,10 @@ enum MergeType
MERGE_GUI_BATCH, //gui and batch files
MERGE_OTHER
};
-MergeType getMergeType(const std::vector<wxString>& filenames); //throw ()
+MergeType getMergeType(const std::vector<Zstring>& filenames); //throw ()
-void convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
-void convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
+void convertConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
+void convertConfig(const std::vector<Zstring>& filenames, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
wxString extractJobName(const wxString& configFilename);
}
diff --git a/lib/recycler.cpp b/lib/recycler.cpp
deleted file mode 100644
index 1c743a0c..00000000
--- a/lib/recycler.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-// **************************************************************************
-// * 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 "recycler.h"
-#include <stdexcept>
-#include <iterator>
-#include <zen/file_handling.h>
-
-#ifdef FFS_WIN
-#include <algorithm>
-#include <functional>
-#include <vector>
-#include <boost/thread/once.hpp>
-#include <zen/dll.h>
-#include <zen/win.h> //includes "windows.h"
-#include <zen/assert_static.h>
-#include <zen/win_ver.h>
-#include <zen/long_path_prefix.h>
-#include "IFileOperation/file_op.h"
-
-#elif defined FFS_LINUX
-#include <zen/scope_guard.h>
-#include <sys/stat.h>
-#include <gio/gio.h>
-#endif
-
-using namespace zen;
-
-
-namespace
-{
-#ifdef FFS_WIN
-/*
-Performance test: delete 1000 files
-------------------------------------
-SHFileOperation - single file 33s
-SHFileOperation - multiple files 2,1s
-IFileOperation - single file 33s
-IFileOperation - multiple files 2,1s
-
-=> SHFileOperation and IFileOperation have nearly IDENTICAL performance characteristics!
-
-Nevertheless, let's use IFileOperation for better error reporting!
-*/
-
-void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw FileError
-{
- if (filesToDelete.empty())
- return;
-
- static bool useIFileOperation = false;
- static boost::once_flag once = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010!
- boost::call_once(once, [] { useIFileOperation = vistaOrLater(); });
-
- if (useIFileOperation) //new recycle bin usage: available since Vista
- {
- std::vector<const wchar_t*> fileNames;
- std::transform(filesToDelete.begin(), filesToDelete.end(),
- std::back_inserter(fileNames), std::mem_fun_ref(&Zstring::c_str));
-
- using namespace fileop;
- const DllFun<MoveToRecycleBinFct> moveToRecycler(getDllName(), moveToRecycleBinFctName);
- const DllFun<GetLastErrorFct> getLastError (getDllName(), getLastErrorFctName);
-
- if (!moveToRecycler || !getLastError)
- throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + fileNames[0] + L"\"") + L"\n\n" + //report first file only... better than nothing
- replaceCpy(_("Cannot load file %x."), L"%x", std::wstring(L"\"") + getDllName() + L"\""));
-
- //#warning moving long file paths to recycler does not work! clarify!
- // std::vector<Zstring> temp;
- // std::transform(filesToDelete.begin(), filesToDelete.end(),
- // std::back_inserter(temp), std::ptr_fun(zen::removeLongPathPrefix)); //::IFileOperation() can't handle \\?\-prefix!
-
- if (!moveToRecycler(&fileNames[0], //array must not be empty
- fileNames.size()))
- {
- std::vector<wchar_t> msgBuffer(2000);
- getLastError(&msgBuffer[0], msgBuffer.size());
-
- throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + fileNames[0] + L"\"") + L"\n\n" + //report first file only... better than nothing
- &msgBuffer[0]);
- }
- }
- else //regular recycle bin usage: available since XP
- {
- Zstring filenameDoubleNull;
- for (std::vector<Zstring>::const_iterator i = filesToDelete.begin(); i != filesToDelete.end(); ++i)
- {
- //#warning moving long file paths to recycler does not work! clarify!
- //filenameDoubleNull += removeLongPathPrefix(*i); //::SHFileOperation() can't handle \\?\-prefix!
- //You should use fully-qualified path names with this function. Using it with relative path names is not thread safe.
- filenameDoubleNull += *i; //::SHFileOperation() can't handle \\?\-prefix!
- filenameDoubleNull += L'\0';
- }
-
- SHFILEOPSTRUCT fileOp = {};
- fileOp.hwnd = nullptr;
- fileOp.wFunc = FO_DELETE;
- fileOp.pFrom = filenameDoubleNull.c_str();
- fileOp.pTo = nullptr;
- fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
- fileOp.fAnyOperationsAborted = false;
- fileOp.hNameMappings = nullptr;
- fileOp.lpszProgressTitle = nullptr;
-
- if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
- {
- throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + filenameDoubleNull.c_str() + L"\"")); //report first file only... better than nothing
- }
- }
-}
-#endif
-}
-
-
-bool zen::moveToRecycleBin(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!
-
-#ifdef FFS_WIN
- //::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL);
- //both SHFileOperation and IFileOperation are not able to delete a folder named "System Volume Information" with normal attributes but shamelessly report success
-
- std::vector<Zstring> fileNames;
- fileNames.push_back(filename);
- ::moveToWindowsRecycler(fileNames); //throw FileError
-
-#elif defined FFS_LINUX
- GFile* file = g_file_new_for_path(filename.c_str()); //never fails according to docu
- ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
-
- GError* error = nullptr;
- ZEN_ON_SCOPE_EXIT(if (error) g_error_free(error););
-
- if (!g_file_trash(file, nullptr, &error))
- {
- if (!error)
- throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", L"\"" + filename + L"\"") + L"\n\n" +
- L"Unknown error.");
-
- //implement same behavior as in Windows: if recycler is not existing, delete permanently
- if (error->code == G_IO_ERROR_NOT_SUPPORTED)
- {
- struct stat fileInfo = {};
- if (::lstat(filename.c_str(), &fileInfo) != 0)
- return false;
-
- if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode))
- removeFile(filename); //throw FileError
- else if (S_ISDIR(fileInfo.st_mode))
- removeDirectory(filename); //throw FileError
- return true;
- }
-
- //assemble error message
- const std::wstring errorMessage = L"Glib Error Code " + numberTo<std::wstring>(error->code) + /* L", " +
- g_quark_to_string(error->domain) + */ L": " + utf8CvrtTo<std::wstring>(error->message);
-
- throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", L"\"" + filename + L"\"") + L"\n\n" +
- errorMessage);
- }
-#endif
- return true;
-}
-
-
-#ifdef FFS_WIN
-zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
-{
- 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
- {
- Zstring rootPath = &buffer[0];
- if (!endsWith(rootPath, FILE_NAME_SEPARATOR)) //a trailing backslash is required
- rootPath += FILE_NAME_SEPARATOR;
-
- SHQUERYRBINFO recInfo = {};
- recInfo.cbSize = sizeof(recInfo);
- HRESULT rv = ::SHQueryRecycleBin(rootPath.c_str(), //__in_opt LPCTSTR pszRootPath,
- &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
- return rv == S_OK ? STATUS_REC_EXISTS : STATUS_REC_MISSING;
- }
- return STATUS_REC_UNKNOWN;
-}
-#elif defined FFS_LINUX
-/*
-We really need access to a similar function to check whether a directory supports trashing and emit a warning if it does not!
-
-The following function looks perfect, alas it is restricted to local files and to the implementation of GIO only:
-
- gboolean _g_local_file_has_trash_dir(const char* dirname, dev_t dir_dev);
- See: http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.h
-
- Just checking for "G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH" is not correct, since we find in
- http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.c
-
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
- writable && parent_info->has_trash_dir);
-
- => We're NOT interested in whether the specified folder can be trashed, but whether it supports thrashing its child elements! (Only support, not actual write access!)
- This renders G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH useless for this purpose.
-*/
-#endif
diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp
index 1b241956..f5a342d2 100644
--- a/lib/resolve_path.cpp
+++ b/lib/resolve_path.cpp
@@ -37,8 +37,7 @@ Zstring resolveRelativePath(Zstring relativeName) //note: ::GetFullPathName() is
&buffer[0], //__out LPTSTR lpBuffer,
nullptr); //__out LPTSTR *lpFilePart
if (charsWritten == 0 || charsWritten >= bufferSize) //theoretically, charsWritten can never be == bufferSize
- //ERROR! Don't do anything
- return relativeName;
+ return relativeName; //ERROR! Don't do anything
return Zstring(&buffer[0], charsWritten);
}
@@ -53,13 +52,7 @@ Zstring resolveRelativePath(const Zstring& relativeName)
{
std::vector<char> buffer(10000);
if (::getcwd(&buffer[0], buffer.size()) != nullptr)
- {
- Zstring workingDir = &buffer[0];
- if (!endsWith(workingDir, FILE_NAME_SEPARATOR))
- workingDir += FILE_NAME_SEPARATOR;
-
- return workingDir + relativeName;
- }
+ return appendSeparator(&buffer[0]) + relativeName;
}
return relativeName;
@@ -177,13 +170,13 @@ bool replaceMacro(wxString& macro) //macro without %-characters, return true if
return false;
//there are equally named environment variables %TIME%, %DATE% existing, so replace these first!
- if (macro.CmpNoCase(wxT("time")) == 0)
+ if (macro.CmpNoCase(L"time") == 0)
{
macro = formatTime<wxString>(L"%H%M%S");
return true;
}
- if (macro.CmpNoCase(wxT("date")) == 0)
+ if (macro.CmpNoCase(L"date") == 0)
{
macro = formatTime<wxString>(FORMAT_ISO_DATE);
return true;
@@ -234,32 +227,27 @@ bool replaceMacro(wxString& macro) //macro without %-characters, return true if
}
-void expandMacros(wxString& text)
+//returns expanded or original string
+wxString expandMacros(const wxString& text)
{
- const wxChar SEPARATOR = '%';
+ const wxChar SEPARATOR = L'%';
- if (text.Find(SEPARATOR) != wxNOT_FOUND)
+ if (contains(text, SEPARATOR))
{
- wxString prefix = text.BeforeFirst(SEPARATOR);
- wxString postfix = text.AfterFirst(SEPARATOR);
- if (postfix.Find(SEPARATOR) != wxNOT_FOUND)
+ wxString prefix = text.BeforeFirst(SEPARATOR);
+ wxString rest = text.AfterFirst(SEPARATOR);
+ if (contains(rest, SEPARATOR))
{
- wxString potentialMacro = postfix.BeforeFirst(SEPARATOR);
- wxString rest = postfix.AfterFirst(SEPARATOR); //text == prefix + SEPARATOR + potentialMacro + SEPARATOR + rest
+ wxString potentialMacro = beforeFirst(rest, SEPARATOR);
+ wxString postfix = afterFirst (rest, SEPARATOR); //text == prefix + SEPARATOR + potentialMacro + SEPARATOR + postfix
if (replaceMacro(potentialMacro))
- {
- expandMacros(rest);
- text = prefix + potentialMacro + rest;
- }
+ return prefix + potentialMacro + expandMacros(postfix);
else
- {
- rest = SEPARATOR + rest;
- expandMacros(rest);
- text = prefix + SEPARATOR + potentialMacro + rest;
- }
+ return prefix + SEPARATOR + potentialMacro + expandMacros(SEPARATOR + postfix);
}
}
+ return text;
}
@@ -286,59 +274,52 @@ private:
#endif
+//networks and cdrom excluded - this should not block
Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on error
{
#ifdef FFS_WIN
- std::vector<wchar_t> volGuid(10000);
+ //FindFirstVolume(): traverses volumes on local hard disks only!
+ //GetLogicalDriveStrings(): traverses all *logical* volumes, including CD-ROM, FreeOTFE virtual volumes
+
+ const DWORD bufferSize = ::GetLogicalDriveStrings(0, nullptr);
+ std::vector<wchar_t> buffer(bufferSize);
- HANDLE hVol = ::FindFirstVolume(&volGuid[0], static_cast<DWORD>(volGuid.size()));
- if (hVol != INVALID_HANDLE_VALUE)
+ const DWORD rv = ::GetLogicalDriveStrings(bufferSize, //__in DWORD nBufferLength,
+ &buffer[0]); //__out LPTSTR lpBuffer
+ if (0 < rv && rv < bufferSize)
{
- ZEN_ON_SCOPE_EXIT(::FindVolumeClose(hVol));
+ //search for matching path in parallel until first hit
+ RunUntilFirstHit<Zstring> findFirstMatch;
- do
+ for (const wchar_t* iter = &buffer[0]; *iter != 0; iter += strLength(iter) + 1) //list terminated by empty c-string
{
- std::vector<wchar_t> volName(MAX_PATH + 1);
-
- if (::GetVolumeInformation(&volGuid[0], //__in_opt LPCTSTR lpRootPathName,
- &volName[0], //__out LPTSTR lpVolumeNameBuffer,
- static_cast<DWORD>(volName.size()), //__in DWORD nVolumeNameSize,
- nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
- nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
- nullptr, //__out_opt LPDWORD lpFileSystemFlags,
- nullptr, //__out LPTSTR lpFileSystemNameBuffer,
- 0)) //__in DWORD nFileSystemNameSize
+ const Zstring path = iter;
+
+ findFirstMatch.addJob([path, volumeName]() -> std::unique_ptr<Zstring>
{
- if (EqualFilename()(volumeName, Zstring(&volName[0])))
- {
- //GetVolumePathNamesForVolumeName is not available for Windows 2000!
- typedef BOOL (WINAPI* GetVolumePathNamesForVolumeNameWFunc)(LPCWSTR lpszVolumeName,
- LPWCH lpszVolumePathNames,
- DWORD cchBufferLength,
- PDWORD lpcchReturnLength);
-
- const SysDllFun<GetVolumePathNamesForVolumeNameWFunc> getVolumePathNamesForVolumeName(L"kernel32.dll", "GetVolumePathNamesForVolumeNameW");
- if (getVolumePathNamesForVolumeName)
- {
- std::vector<wchar_t> buffer(10000);
- DWORD returnedLen = 0;
- if (getVolumePathNamesForVolumeName(&volGuid[0], //__in LPCTSTR lpszVolumeName,
- &buffer[0], //__out LPTSTR lpszVolumePathNames,
- static_cast<DWORD>(buffer.size()), //__in DWORD cchBufferLength,
- &returnedLen)) //__out PDWORD lpcchReturnLength
- {
- //Attention: in contrast to documentation, this function may write a *single* 0 into
- //buffer if volGuid does not have any associated volume paths (e.g. a hidden volume)
- const Zstring volPath(&buffer[0]);
- if (!volPath.empty())
- return volPath; //return first path name in double-null terminated list!
- }
- }
- return &volGuid[0]; //GUID looks ugly, but should be working correctly
- }
- }
+ UINT type = ::GetDriveType(path.c_str()); //non-blocking call!
+ if (type == DRIVE_REMOTE ||
+ type == DRIVE_CDROM)
+ return nullptr;
+
+ //next call seriously blocks for non-existing network drives!
+ std::vector<wchar_t> volName(MAX_PATH + 1); //docu says so
+
+ if (::GetVolumeInformation(path.c_str(), //__in_opt LPCTSTR lpRootPathName,
+ &volName[0], //__out LPTSTR lpVolumeNameBuffer,
+ static_cast<DWORD>(volName.size()), //__in DWORD nVolumeNameSize,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
+ if (EqualFilename()(volumeName, Zstring(&volName[0])))
+ return zen::make_unique<Zstring>(path);
+ return nullptr;
+ });
}
- while (::FindNextVolume(hVol, &volGuid[0], static_cast<DWORD>(volGuid.size())));
+ if (auto result = findFirstMatch.get()) //blocks until ready
+ return *result;
}
#elif defined FFS_LINUX
@@ -358,62 +339,58 @@ Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on er
#ifdef FFS_WIN
-//attention: this call may seriously block if network volume is not available!!!
+//networks and cdrom excluded - this should not block
Zstring volumePathToName(const Zstring& volumePath) //return empty string on error
{
- const DWORD bufferSize = MAX_PATH + 1;
- std::vector<wchar_t> volName(bufferSize);
-
- if (::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
- &volName[0], //__out LPTSTR lpVolumeNameBuffer,
- bufferSize, //__in DWORD nVolumeNameSize,
- nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
- nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
- nullptr, //__out_opt LPDWORD lpFileSystemFlags,
- nullptr, //__out LPTSTR lpFileSystemNameBuffer,
- 0)) //__in DWORD nFileSystemNameSize
+ UINT rv = ::GetDriveType(volumePath.c_str()); //non-blocking call!
+ if (rv != DRIVE_REMOTE &&
+ rv != DRIVE_CDROM)
{
- return &volName[0];
+ 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,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
+ return &buffer[0];
}
return Zstring();
}
#endif
-void expandVolumeName(Zstring& text) // [volname]:\folder [volname]\folder [volname]folder -> C:\folder
+//expand volume name if possible, return original input otherwise
+Zstring expandVolumeName(const Zstring& text) // [volname]:\folder [volname]\folder [volname]folder -> C:\folder
{
//this would be a nice job for a C++11 regex...
-
//we only expect the [.*] pattern at the beginning => do not touch dir names like "C:\somedir\[stuff]"
- trim(text, true, false);
+ Zstring textTmp = text;
+ trim(textTmp, true, false);
- if (startsWith(text, Zstr("[")))
+ if (startsWith(textTmp, Zstr("[")))
{
- size_t posEnd = text.find(Zstr("]"));
+ size_t posEnd = textTmp.find(Zstr("]"));
if (posEnd != Zstring::npos)
{
- Zstring volname = Zstring(text.c_str() + 1, posEnd - 1);
- Zstring after = Zstring(text.c_str() + posEnd + 1);
+ Zstring volname = Zstring(textTmp.c_str() + 1, posEnd - 1);
+ Zstring rest = Zstring(textTmp.c_str() + posEnd + 1);
- if (startsWith(after, Zstr(':')))
- after = afterFirst(after, Zstr(':'));
- if (startsWith(after, FILE_NAME_SEPARATOR))
- after = afterFirst(after, FILE_NAME_SEPARATOR);
+ if (startsWith(rest, Zstr(':')))
+ rest = afterFirst(rest, Zstr(':'));
+ if (startsWith(rest, FILE_NAME_SEPARATOR))
+ rest = afterFirst(rest, FILE_NAME_SEPARATOR);
//[.*] pattern was found...
if (!volname.empty())
{
- Zstring volPath = volumenNameToPath(volname); //return empty string on error
+ Zstring volPath = volumenNameToPath(volname); //should not block?!
if (!volPath.empty())
- {
- if (!endsWith(volPath, FILE_NAME_SEPARATOR))
- volPath += FILE_NAME_SEPARATOR;
-
- text = volPath + after;
- //successfully replaced pattern
- return;
- }
+ return appendSeparator(volPath) + rest; //successfully replaced pattern
}
//error: did not find corresponding volume name:
@@ -425,13 +402,13 @@ void expandVolumeName(Zstring& text) // [volname]:\folder [volname]\folde
C:\Program Files\FreeFileSync\[FFS USB]\FreeFileSync\
*/
#ifdef FFS_WIN
- text = L"?:\\[" + volname + L"]\\" + after;
+ return L"?:\\[" + volname + L"]\\" + rest;
#elif defined FFS_LINUX
- text = "/.../[" + volname + "]/" + after;
+ return "/.../[" + volname + "]/" + rest;
#endif
- return;
}
}
+ return text;
}
}
@@ -445,20 +422,14 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less
dirname[1] == L':' &&
dirname[2] == L'\\')
{
- //attention: "volumePathToName()" will seriously block if network volume is not available!!!
- boost::unique_future<Zstring> futVolName = zen::async([=] { return volumePathToName(Zstring(dirname.c_str(), 3)); });
- if (futVolName.timed_wait(boost::posix_time::seconds(1)))
- {
- Zstring volname = futVolName.get();
- if (!volname.empty())
- output.insert(L"[" + volname + L"]" + Zstring(dirname.c_str() + 2));
- }
+ Zstring volname = volumePathToName(Zstring(dirname.c_str(), 3)); //should not block
+ if (!volname.empty())
+ output.insert(L"[" + volname + L"]" + Zstring(dirname.c_str() + 2));
}
//2. replace volume name by volume path: [SYSTEM]\dirname -> c:\dirname
{
- Zstring testVolname = dirname;
- expandVolumeName(testVolname);
+ Zstring testVolname = expandVolumeName(dirname); //should not block
if (testVolname != dirname)
if (output.insert(testVolname).second)
getDirectoryAliasesRecursive(testVolname, output); //recurse!
@@ -504,11 +475,10 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less
//4. replace (all) macros: %USERPROFILE% -> C:\Users\username
{
- wxString testMacros = toWx(dirname);
- expandMacros(testMacros);
- if (toZ(testMacros) != dirname)
- if (output.insert(toZ(testMacros)).second)
- getDirectoryAliasesRecursive(toZ(testMacros), output); //recurse!
+ Zstring testMacros = toZ(expandMacros(toWx(dirname)));
+ if (testMacros != dirname)
+ if (output.insert(testMacros).second)
+ getDirectoryAliasesRecursive(testMacros, output); //recurse!
}
}
@@ -535,19 +505,16 @@ Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw()
{
//Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names.
- wxString dirnameTmp = toWx(dirString);
- expandMacros(dirnameTmp);
-
- Zstring output = toZ(dirnameTmp);
+ Zstring dirname = toZ(expandMacros(toWx(dirString)));
- expandVolumeName(output);
+ dirname = expandVolumeName(dirname); //should not block
//remove leading/trailing whitespace
- trim(output, true, false);
- while (endsWith(output, " ")) //don't remove all whitespace from right, e.g. 0xa0 may be used as part of dir name
- output.resize(output.size() - 1);
+ trim(dirname, true, false);
+ while (endsWith(dirname, " ")) //don't remove all whitespace from right, e.g. 0xa0 may be used as part of dir name
+ dirname.resize(dirname.size() - 1);
- if (output.empty()) //an empty string would later be resolved as "\"; this is not desired
+ if (dirname.empty()) //an empty string would later be resolved as "\"; this is not desired
return Zstring();
/*
@@ -560,12 +527,9 @@ Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw()
WINDOWS/LINUX:
- detection of dependent directories, e.g. "\" and "C:\test"
*/
- output = resolveRelativePath(output);
-
- if (!endsWith(output, FILE_NAME_SEPARATOR))
- output += FILE_NAME_SEPARATOR;
+ dirname = resolveRelativePath(dirname);
- return output;
+ return appendSeparator(dirname);
}
@@ -585,7 +549,8 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio
//if (::GetFileAttributes((driveLetter + L'\\').c_str()) == INVALID_FILE_ATTRIBUTES) <- this will seriously block if network is not reachable!!!
- const Zstring dirname = removeLongPathPrefix(dirnameOrig);
+ Zstring dirname = removeLongPathPrefix(dirnameOrig);
+ trim(dirname, true, false);
//1. local path
if (dirname.size() >= 2 && iswalpha(dirname[0]) && dirname[1] == L':')
diff --git a/lib/resources.cpp b/lib/resources.cpp
index f5def2c6..3ae24d1d 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -64,21 +64,21 @@ GlobalResources::GlobalResources()
const wxString name = entry->GetName();
//generic image loading
- if (name.EndsWith(wxT(".png")))
+ if (name.EndsWith(L".png"))
bitmaps.insert(std::make_pair(name, wxImage(resourceFile, wxBITMAP_TYPE_PNG)));
- //else if (name == wxT("money.gif"))
+ //else if (name == L"money.gif")
// loadAnimFromZip(resourceFile, animationMoney);
- else if (name == wxT("working.gif"))
+ else if (name == L"working.gif")
loadAnimFromZip(resourceFile, animationSync);
}
}
#ifdef FFS_WIN
//for compatibility it seems we need to stick with a "real" icon
- programIcon = wxIcon(wxT("A_PROGRAM_ICON"));
+ programIcon = wxIcon(L"A_PROGRAM_ICON");
#else
//use big logo bitmap for better quality
- programIcon.CopyFromBitmap(getImageInt(wxT("FreeFileSync.png")));
+ programIcon.CopyFromBitmap(getImageInt(L"FreeFileSync.png"));
//attention: this is the reason we need a member getImage -> it must not implicitly create static object instance!!!
//erroneously calling static object constructor twice will deadlock on Linux!!
#endif
@@ -87,8 +87,8 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& imageName) const
{
- auto iter = bitmaps.find(imageName.Find(L'.') == wxNOT_FOUND ? //assume .png ending if nothing else specified
- imageName + wxT(".png") :
+ auto iter = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified
+ imageName + L".png" :
imageName);
if (iter != bitmaps.end())
return iter->second;
diff --git a/lib/shadow.cpp b/lib/shadow.cpp
index 0a34ae5a..f4d7f3af 100644
--- a/lib/shadow.cpp
+++ b/lib/shadow.cpp
@@ -40,53 +40,49 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m
class ShadowCopy::ShadowVolume
{
public:
- ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError)
- createShadowCopy (getDllName(), createShadowCopyFctName),
- releaseShadowCopy(getDllName(), releaseShadowCopyFctName),
- getShadowVolume (getDllName(), getShadowVolumeFctName),
+ ShadowVolume(const Zstring& volumeNamePf) : //throw(FileError)
+ createShadowCopy (getDllName(), funName_createShadowCopy),
+ releaseShadowCopy(getDllName(), funName_releaseShadowCopy),
+ getShadowVolume (getDllName(), funName_getShadowVolume),
+ getLastError (getDllName(), funName_getLastError),
backupHandle(nullptr)
{
//VSS does not support running under WOW64 except for Windows XP and Windows Server 2003
//(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx)
if (runningWOW64())
- throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
- _("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version."));
+ throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
+ _("Please use FreeFileSync 64-bit version to create shadow copies on this system."));
//check if shadow copy dll was loaded correctly
- if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume)
- throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
- replaceCpy(_("Cannot load file %x."), L"%x", std::wstring(L"\"") + getDllName() + L"\""));
+ if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume || !getLastError)
+ throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
+ replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
//---------------------------------------------------------------------------------------------------------
//start shadow volume copy service:
- const unsigned int BUFFER_SIZE = 10000;
- std::vector<wchar_t> msgBuffer(BUFFER_SIZE);
- backupHandle = createShadowCopy(volumeNameFormatted.c_str(),
- &msgBuffer[0], BUFFER_SIZE);
+ backupHandle = createShadowCopy(volumeNamePf.c_str());
if (!backupHandle)
- throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
- &msgBuffer[0] + L" Volume: \"" + volumeNameFormatted + L"\"");
+ throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
+ getLastError() + L" Volume: " + fmtFileName(volumeNamePf));
- std::vector<wchar_t> volBuffer(BUFFER_SIZE);
- getShadowVolume(backupHandle, &volBuffer[0], BUFFER_SIZE);
- shadowVol = Zstring(&volBuffer[0]) + FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
+ shadowVolPf = appendSeparator(getShadowVolume(backupHandle)); //shadowVolName NEVER has a trailing backslash
}
~ShadowVolume() { releaseShadowCopy(backupHandle); } //fast! no performance optimization necessary
- Zstring getShadowVolumeName() const { return shadowVol; } //with trailing path separator
+ Zstring geNamePf() const { return shadowVolPf; } //with trailing path separator
private:
ShadowVolume(const ShadowVolume&);
ShadowVolume& operator=(const ShadowVolume&);
- const DllFun<CreateShadowCopyFct> createShadowCopy;
- const DllFun<ReleaseShadowCopyFct> releaseShadowCopy;
- const DllFun<GetShadowVolumeFct> getShadowVolume;
-
- Zstring shadowVol;
+ const DllFun<FunType_createShadowCopy> createShadowCopy;
+ const DllFun<FunType_releaseShadowCopy> releaseShadowCopy;
+ const DllFun<FunType_getShadowVolume> getShadowVolume;
+ const DllFun<FunType_getLastError> getLastError;
+ Zstring shadowVolPf;
ShadowHandle backupHandle;
};
//#############################################################################################################
@@ -94,34 +90,33 @@ private:
Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
{
- std::vector<wchar_t> volBuffer(1000);
+ DWORD bufferSize = 10000;
+ std::vector<wchar_t> volBuffer(bufferSize);
if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName,
&volBuffer[0], //__out LPTSTR lpszVolumePathName,
- static_cast<DWORD>(volBuffer.size()))) //__in DWORD cchBufferLength
- throw FileError(_("Cannot determine volume name for file:") + L"\n\"" + inputFile + L"\"");
+ bufferSize)) //__in DWORD cchBufferLength
+ throw FileError(replaceCpy(_("Path %x does not contain a volume name."), L"%x", fmtFileName(inputFile)));
- Zstring volumeNameFormatted = &volBuffer[0];
- if (!endsWith(volumeNameFormatted, FILE_NAME_SEPARATOR))
- volumeNameFormatted += FILE_NAME_SEPARATOR;
+ const Zstring volumeNamePf = appendSeparator(&volBuffer[0]);
//input file is always absolute! directory formatting takes care of this! Therefore volume name can always be found.
- const size_t pos = inputFile.find(volumeNameFormatted); //inputFile needs NOT to begin with volumeNameFormatted: consider for example \\?\ prefix!
+ const size_t pos = inputFile.find(volumeNamePf); //inputFile needs NOT to begin with volumeNamePf: consider for example \\?\ prefix!
if (pos == Zstring::npos)
{
std::wstring msg = _("Volume name %x not part of file name %y!");
- replace(msg, L"%x", std::wstring(L"\"") + volumeNameFormatted + L"\"", false);
- replace(msg, L"%y", std::wstring(L"\"") + inputFile + L"\"", false);
+ replace(msg, L"%x", fmtFileName(volumeNamePf), false);
+ replace(msg, L"%y", fmtFileName(inputFile), false);
throw FileError(msg);
}
//get or create instance of shadow volume
- VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted);
+ VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNamePf);
if (iter == shadowVol.end())
{
- auto newEntry = std::make_shared<ShadowVolume>(volumeNameFormatted);
- iter = shadowVol.insert(std::make_pair(volumeNameFormatted, newEntry)).first;
+ auto newEntry = std::make_shared<ShadowVolume>(volumeNamePf);
+ iter = shadowVol.insert(std::make_pair(volumeNamePf, newEntry)).first;
}
//return filename alias on shadow copy volume
- return iter->second->getShadowVolumeName() + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length());
+ return iter->second->geNamePf() + Zstring(inputFile.c_str() + pos + volumeNamePf.length());
}
diff --git a/lib/shadow.h b/lib/shadow.h
index 2d933840..5335e95d 100644
--- a/lib/shadow.h
+++ b/lib/shadow.h
@@ -20,7 +20,7 @@ class ShadowCopy //buffer access to Windows Volume Shadow Copy Service
public:
ShadowCopy() {}
- Zstring makeShadowCopy(const Zstring& inputFile); //throw(FileError); returns filename on shadow copy
+ Zstring makeShadowCopy(const Zstring& inputFile); //throw FileError; returns filename on shadow copy
private:
ShadowCopy(const ShadowCopy&);
diff --git a/lib/statistics.h b/lib/statistics.h
deleted file mode 100644
index bddf129d..00000000
--- a/lib/statistics.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// **************************************************************************
-// * 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 STATISTICS_H_INCLUDED
-#define STATISTICS_H_INCLUDED
-
-#include <vector>
-#include <map>
-#include <memory>
-#include <wx/defs.h>
-#include <wx/string.h>
-#include <wx/stopwatch.h>
-#include <zen/deprecate.h>
-
-class RetrieveStatistics
-{
-public:
- ZEN_DEPRECATE ~RetrieveStatistics(); //remove code after measurements!
- void writeEntry(double value, int objects);
-
-private:
- struct StatEntry
- {
- long time;
- int objects;
- double value;
- };
- std::vector<StatEntry> data;
- wxStopWatch timer;
-};
-
-
-class Statistics
-{
-public:
- Statistics(int totalObjectCount,
- double totalDataAmount,
- unsigned windowSizeRemainingTime, //time in ms
- unsigned windowSizeBytesPerSecond); //time in ms
-
- void addMeasurement(int objectsCurrent, double dataCurrent);
- void setNewTotal(int totalObjectCount, double totalDataAmount); //may change during sync!
-
- wxString getRemainingTime() const; //returns the remaining time in milliseconds
- wxString getBytesPerSecond() const;
-
- void pauseTimer();
- void resumeTimer();
-
-private:
- int objectsTotal;
- double dataTotal;
-
- const unsigned int windowSizeRemTime; //"window width" of statistics used for calculation of remaining time in ms
- const unsigned int windowSizeBPS; //
- const unsigned int windowMax;
-
- struct Record
- {
- int objects; //object count
- double data; //unit: bytes
- };
-
- typedef std::multimap<long, Record> TimeRecordMap; //time, unit: milliseconds
- TimeRecordMap measurements; //
-
- wxStopWatch timer;
-};
-
-#endif // STATISTICS_H_INCLUDED
diff --git a/lib/status_handler.cpp b/lib/status_handler.cpp
index 5e75b60e..d9655c48 100644
--- a/lib/status_handler.cpp
+++ b/lib/status_handler.cpp
@@ -6,9 +6,12 @@
#include "status_handler.h"
#include <wx/app.h>
-#include <ctime>
+#include <zen/tick_count.h>
-void updateUiNow()
+using namespace zen;
+
+
+void zen::updateUiNow()
{
//process UI events and prevent application from "not responding" -> NO performance issue!
wxTheApp->Yield();
@@ -17,15 +20,16 @@ void updateUiNow()
// wxTheApp->Dispatch();
}
-
-bool updateUiIsAllowed()
+namespace
{
- const std::clock_t CLOCK_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * CLOCKS_PER_SEC / 1000;
+const std::int64_t TICKS_UPDATE_INTERVAL = UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
+TickVal lastExec = getTicks();
+};
- static std::clock_t lastExec = 0;
- const std::clock_t now = std::clock(); //this is quite fast: 2 * 10^-5
-
- if (now - lastExec >= CLOCK_UPDATE_INTERVAL) //perform ui updates not more often than necessary
+bool zen::updateUiIsAllowed()
+{
+ const TickVal now = getTicks(); //0 on error
+ if (now - lastExec >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary
{
lastExec = now;
return true;
diff --git a/lib/status_handler.h b/lib/status_handler.h
index b246e49c..7b7cb3d7 100644
--- a/lib/status_handler.h
+++ b/lib/status_handler.h
@@ -10,9 +10,10 @@
#include "../process_callback.h"
#include <string>
#include <zen/int64.h>
+#include <zen/i18n.h>
-const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
-
+namespace zen
+{
bool updateUiIsAllowed(); //test if a specific amount of time is over
void updateUiNow(); //do the updating
@@ -31,11 +32,42 @@ struct AbortCallback
};
-//actual callback implementation will have to satisfy "process" and "gui"
-class StatusHandler : public ProcessCallback, public AbortCallback
+//common statistics "everybody" needs
+struct Statistics
+{
+ virtual ~Statistics() {}
+
+ virtual ProcessCallback::Phase currentPhase() const = 0;
+
+ virtual int getObjectsCurrent(ProcessCallback::Phase phaseId) const = 0;
+ virtual int getObjectsTotal (ProcessCallback::Phase phaseId) const = 0;
+
+ virtual Int64 getDataCurrent(ProcessCallback::Phase phaseId) const = 0;
+ virtual Int64 getDataTotal (ProcessCallback::Phase phaseId) const = 0;
+
+ virtual const std::wstring& currentStatusText() const = 0;
+};
+
+
+//partial callback implementation with common functionality for "batch", "GUI/Compare" and "GUI/Sync"
+class StatusHandler : public ProcessCallback, public AbortCallback, public Statistics
{
public:
- StatusHandler() : abortRequested(false) {}
+ StatusHandler() : currentPhase_(PHASE_NONE),
+ numbersCurrent_(4), //init with phase count
+ numbersTotal_ (4), //
+ abortRequested(false) {}
+
+protected:
+ //implement parts of ProcessCallback
+ virtual void initNewPhase(int objectsTotal, Int64 dataTotal, Phase phaseId)
+ {
+ currentPhase_ = phaseId;
+ refNumbers(numbersTotal_, currentPhase_) = std::make_pair(objectsTotal, dataTotal);
+ }
+
+ virtual void updateProcessedData(int objectsDelta, Int64 dataDelta) { updateData(numbersCurrent_, objectsDelta, dataDelta); } //note: these methods should NOT throw in order
+ virtual void updateTotalData (int objectsDelta, Int64 dataDelta) { updateData(numbersTotal_ , objectsDelta, dataDelta); } //to properly allow undoing setting of statistics!
virtual void requestUiRefresh()
{
@@ -46,12 +78,68 @@ public:
abortThisProcess(); //abort can be triggered by requestAbortion()
}
+ virtual void reportStatus(const std::wstring& text) { statusText_ = text; requestUiRefresh(); /*throw AbortThisProcess */ }
+ virtual void reportInfo (const std::wstring& text) { statusText_ = text; requestUiRefresh(); /*throw AbortThisProcess */ } //log text in derived class
+
+ //implement AbortCallback
+ virtual void requestAbortion()
+ {
+ abortRequested = true;
+ statusText_ =_("Abort requested: Waiting for current operation to finish...");
+ } //this does NOT call abortThisProcess immediately, but when we're out of the C GUI call stack
+
+ //implement Statistics
+ virtual Phase currentPhase() const { return currentPhase_; }
+
+ virtual int getObjectsCurrent(Phase phaseId) const { return refNumbers(numbersCurrent_, phaseId).first; }
+ virtual int getObjectsTotal (Phase phaseId) const { assert(phaseId != PHASE_SCANNING); return refNumbers(numbersTotal_ , phaseId).first; }
+
+ virtual Int64 getDataCurrent(Phase phaseId) const { assert(phaseId != PHASE_SCANNING); return refNumbers(numbersCurrent_, phaseId).second; }
+ virtual Int64 getDataTotal (Phase phaseId) const { assert(phaseId != PHASE_SCANNING); return refNumbers(numbersTotal_ , phaseId).second; }
+
+ virtual const std::wstring& currentStatusText() const { return statusText_; }
+
+ //enrich this interface
virtual void abortThisProcess() = 0;
- virtual void requestAbortion() { abortRequested = true; } //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished)
- bool abortIsRequested() { return abortRequested; }
+
+ bool abortIsRequested() const { return abortRequested; }
private:
+ typedef std::vector<std::pair<int, Int64>> StatNumbers;
+
+ void updateData(StatNumbers& num, int objectsDelta, Int64 dataDelta)
+ {
+ auto& st = refNumbers(num, currentPhase_);
+ st.first += objectsDelta;
+ st.second += dataDelta;
+ }
+
+ static const std::pair<int, Int64>& refNumbers(const StatNumbers& num, Phase phaseId)
+ {
+ switch (phaseId)
+ {
+ case PHASE_SCANNING:
+ return num[0];
+ case PHASE_COMPARING_CONTENT:
+ return num[1];
+ case PHASE_SYNCHRONIZING:
+ return num[2];
+ case PHASE_NONE:
+ break;
+ }
+ assert(false);
+ return num[3]; //dummy entry!
+ }
+
+ static std::pair<int, Int64>& refNumbers(StatNumbers& num, Phase phaseId) { return const_cast<std::pair<int, Int64>&>(refNumbers(static_cast<const StatNumbers&>(num), phaseId)); }
+
+ Phase currentPhase_;
+ StatNumbers numbersCurrent_;
+ StatNumbers numbersTotal_;
+ std::wstring statusText_;
+
bool abortRequested;
};
+}
#endif // STATUSHANDLER_H_INCLUDED
diff --git a/lib/status_handler_impl.h b/lib/status_handler_impl.h
index 7141d75c..10890dbe 100644
--- a/lib/status_handler_impl.h
+++ b/lib/status_handler_impl.h
@@ -8,7 +8,7 @@
#define STATUSHANDLER_IMPL_H_INCLUDED
#include <zen/file_error.h>
-#include "status_handler.h"
+#include "process_callback.h"
template <typename Function> inline
bool tryReportingError(Function cmd, ProcessCallback& handler) //return "true" on success, "false" if error was ignored
diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp
index 10bb698a..3f6cc0be 100644
--- a/lib/xml_base.cpp
+++ b/lib/xml_base.cpp
@@ -31,7 +31,7 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
if (!startsWith(fileBegin, xmlBegin) &&
!startsWith(fileBegin, zen::BYTE_ORDER_MARK_UTF8 + xmlBegin)) //respect BOM!
- throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + filename + L"\"");
+ throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
}
const zen::UInt64 fs = zen::getFilesize(filename); //throw FileError
@@ -40,12 +40,12 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
FileInput inputFile(filename); //throw FileError
const size_t bytesRead = inputFile.read(&stream[0], stream.size()); //throw FileError
if (bytesRead < to<size_t>(fs))
- throw FfsXmlError(_("Error reading file:") + L"\n\"" + filename + L"\"");
+ throw FfsXmlError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename)));
}
catch (const FileError& error)
{
if (!fileExists(filename))
- throw FfsXmlError(_("File does not exist:") + L"\n\"" + filename+ L"\"");
+ throw FfsXmlError(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)));
throw FfsXmlError(error.toString());
}
@@ -54,9 +54,13 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
{
zen::parse(stream, doc); //throw XmlParsingError
}
- catch (const XmlParsingError&)
+ catch (const XmlParsingError& e)
{
- throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + filename + L"\"");
+ throw FfsXmlError(
+ replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
+ L"%x", fmtFileName(filename)),
+ L"%y", numberTo<std::wstring>(e.row)),
+ L"%z", numberTo<std::wstring>(e.col)));
}
}
@@ -77,7 +81,7 @@ const std::wstring xmlAccess::getErrorMessageFormatted(const XmlIn& in)
}
-void xmlAccess::saveXmlDocument(const zen::XmlDoc& doc, const Zstring& filename) //throw (FfsXmlError)
+void xmlAccess::saveXmlDocument(const zen::XmlDoc& doc, const Zstring& filename) //throw FfsXmlError
{
std::string stream = serialize(doc); //throw ()
@@ -98,7 +102,7 @@ void xmlAccess::saveXmlDocument(const zen::XmlDoc& doc, const Zstring& filename)
try
{
FileOutput outputFile(filename, FileOutput::ACC_OVERWRITE); //throw FileError
- outputFile.write(stream.c_str(), stream.length()); //
+ outputFile.write(stream.c_str(), stream.length()); //
}
catch (const FileError& error) //more detailed error messages than with wxWidgets
{
diff --git a/process_callback.h b/process_callback.h
index 77b2987f..c7681bb0 100644
--- a/process_callback.h
+++ b/process_callback.h
@@ -11,24 +11,26 @@
#include <zen/int64.h>
//interface for comparison and synchronization process status updates (used by GUI or Batch mode)
-
+const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary,
+//100 seems to be a good value with only a minimal performance loss; also used by Win 7 copy progress bar
+//this one is required by async directory existence check!
//report status during comparison and synchronization
struct ProcessCallback
{
virtual ~ProcessCallback() {}
- //identifiers of different phases
- enum Process
+ //these methods have to be implemented in the derived classes to handle error and status information
+
+ //notify synchronization phases
+ enum Phase
{
- PROCESS_NONE = 10,
- PROCESS_SCANNING,
- PROCESS_COMPARING_CONTENT,
- PROCESS_SYNCHRONIZING
+ PHASE_NONE, //initial status
+ PHASE_SCANNING,
+ PHASE_COMPARING_CONTENT,
+ PHASE_SYNCHRONIZING
};
-
- //these methods have to be implemented in the derived classes to handle error and status information
- virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
+ virtual void initNewPhase(int objectsTotal, zen::Int64 dataTotal, Phase phaseId) = 0; //informs about the total amount of data that will be processed in this phase
//note: this one must NOT throw in order to properly allow undoing setting of statistics!
//it is in general paired with a call to requestUiRefresh() to compensate!
@@ -36,11 +38,12 @@ struct ProcessCallback
virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta) = 0; //
/*the estimated total may change *during* sync:
1. move file -> fallback to copy + delete
- 2. file copy, actual size changed after comparison
+ 2. file copy, actual size changed after comparison or file contains significant ADS data
3. auto-resolution for failed create operations due to missing source
4. directory deletion: may contain more items than scanned by FFS: excluded by filter
5. delete directory to recycler or move to user-defined dir on same volume: no matter how many sub-elements exist, this is only 1 object to process!
- 6. user-defined deletion directory on different volume: full file copy required (instead of move) */
+ 6. user-defined deletion directory on different volume: full file copy required (instead of move)
+ 7. Copy sparse files */
//opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
virtual void requestUiRefresh() = 0; //throw ?
diff --git a/structures.cpp b/structures.cpp
index 0a7eda2b..5b2d4336 100644
--- a/structures.cpp
+++ b/structures.cpp
@@ -230,7 +230,7 @@ Int64 resolve(size_t value, UnitTime unit, Int64 defaultVal)
{
case UTIME_NONE:
return defaultVal;
-
+
case UTIME_TODAY:
locTimeStruc.second = 0; //0-61
locTimeStruc.minute = 0; //0-59
diff --git a/structures.h b/structures.h
index 39d6c03a..db912662 100644
--- a/structures.h
+++ b/structures.h
@@ -370,13 +370,13 @@ struct MainConfiguration
#ifdef FFS_WIN
globalFilter(Zstr("*"),
Zstr("\\System Volume Information\\\n")
- Zstr("\\RECYCLED\\\n")
+ Zstr("\\$Recycle.Bin\\\n")
Zstr("\\RECYCLER\\\n")
- Zstr("\\$Recycle.Bin\\")) {}
+ Zstr("\\RECYCLED\\\n")) {}
#elif defined FFS_LINUX
globalFilter(Zstr("*"),
Zstr("/.Trash-*/\n")
- Zstr("/.recycle/")) {}
+ Zstr("/.recycle/\n")) {}
#endif
CompConfig cmpConfig; //global compare settings: may be overwritten by folder pair settings
diff --git a/synchronization.cpp b/synchronization.cpp
index 1528ac27..edc38303 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -8,15 +8,13 @@
#include <memory>
#include <deque>
#include <stdexcept>
-#include <wx/utils.h>
-#include <wx/log.h>
-#include <wx/file.h>
+#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>
+#include <zen/recycler.h>
#include "lib/resolve_path.h"
-#include "lib/recycler.h"
#include "lib/db_file.h"
#include "lib/dir_exist_async.h"
#include "lib/cmp_filetime.h"
@@ -294,38 +292,24 @@ std::vector<zen::FolderPairSyncCfg> zen::extractSyncCfg(const MainConfiguration&
}
//------------------------------------------------------------------------------------------------------------
-namespace
-{
-bool synchronizationNeeded(const SyncStatistics& statisticsTotal)
-{
- return statisticsTotal.getCreate() +
- statisticsTotal.getUpdate() +
- statisticsTotal.getDelete() +
- //conflicts (unless excluded) justify a sync! Also note: if this method returns false, no warning about unresolved conflicts were shown!
- statisticsTotal.getConflict() != 0;
-}
-}
-
//test if user accidentally tries to sync the wrong folders
bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
{
//initial file copying shall not be detected as major difference
- if (folderPairStat.getCreate<LEFT_SIDE>() == 0 &&
- folderPairStat.getUpdate () == 0 &&
- folderPairStat.getDelete () == 0 &&
- folderPairStat.getConflict() == 0) return false;
- if (folderPairStat.getCreate<RIGHT_SIDE>() == 0 &&
- folderPairStat.getUpdate () == 0 &&
- folderPairStat.getDelete () == 0 &&
- folderPairStat.getConflict() == 0) return false;
-
- const int changedRows = folderPairStat.getCreate () +
- folderPairStat.getUpdate () +
- folderPairStat.getDelete () +
- folderPairStat.getConflict();
-
- return changedRows >= 10 && changedRows > 0.5 * folderPairStat.getRowCount();
+ if ((folderPairStat.getCreate<LEFT_SIDE >() == 0 ||
+ folderPairStat.getCreate<RIGHT_SIDE>() == 0) &&
+ folderPairStat.getUpdate () == 0 &&
+ folderPairStat.getDelete () == 0 &&
+ folderPairStat.getConflict() == 0)
+ return false;
+
+ const int nonMatchingRows = folderPairStat.getCreate() +
+ //folderPairStat.getUpdate() + -> not relevant when testing for "wrong folder selected"
+ folderPairStat.getDelete () +
+ folderPairStat.getConflict(); //?
+
+ return nonMatchingRows >= 10 && nonMatchingRows > 0.5 * folderPairStat.getRowCount();
}
//#################################################################################################################
@@ -343,20 +327,13 @@ add some postfix to alternate deletion directory: deletionDirectory\<prefix>2010
*/
Zstring getSessionDeletionDir(const Zstring& deletionDirectory, const Zstring& prefix = Zstring())
{
- Zstring formattedDir = deletionDirectory;
- if (formattedDir.empty())
+ if (deletionDirectory.empty())
return Zstring(); //no valid directory for deletion specified (checked later)
- if (!endsWith(formattedDir, FILE_NAME_SEPARATOR))
- formattedDir += FILE_NAME_SEPARATOR;
-
- formattedDir += prefix;
- formattedDir += formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"));
+ const Zstring formattedDir = appendSeparator(deletionDirectory) + prefix + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"));
//ensure that session directory does not yet exist (must be unique)
Zstring output = formattedDir;
-
- //ensure uniqueness
for (int i = 1; zen::somethingExists(output); ++i)
output = formattedDir + Zchar('_') + numberTo<Zstring>(i);
@@ -438,32 +415,32 @@ DeletionHandling::DeletionHandling(DeletionPolicy handleDel,
{
#ifdef FFS_WIN
if (baseDirPf.empty() ||
- (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDirPf) != STATUS_REC_EXISTS))
+ (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)
#endif
switch (deletionType)
{
case DELETE_PERMANENTLY:
- txtRemovingFile = replaceCpy(_("Deleting file %x" ), L"%x", L"\"%x\"", false);
- txtRemovingDirectory = replaceCpy(_("Deleting folder %x" ), L"%x", L"\"%x\"", false);
- txtRemovingSymlink = replaceCpy(_("Deleting symbolic link %x"), L"%x", L"\"%x\"", false);
+ txtRemovingFile = _("Deleting file %x" );
+ txtRemovingDirectory = _("Deleting folder %x" );
+ txtRemovingSymlink = _("Deleting symbolic link %x");
break;
case MOVE_TO_RECYCLE_BIN:
sessionDelDir = getSessionDeletionDir(baseDirPf_, Zstr("FFS "));
- txtRemovingFile = replaceCpy(_("Moving file %x to recycle bin" ), L"%x", L"\"%x\"", false);
- txtRemovingDirectory = replaceCpy(_("Moving folder %x to recycle bin" ), L"%x", L"\"%x\"", false);
- txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to recycle bin"), L"%x", L"\"%x\"", false);
+ 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:
sessionDelDir = getSessionDeletionDir(custDelFolder);
- txtRemovingFile = replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
- txtRemovingDirectory = replaceCpy(replaceCpy(_("Moving folder %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
- txtRemovingSymlink = replaceCpy(replaceCpy(_("Moving symbolic link %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo<std::wstring>(custDelFolder) + L"\"", false);
+ txtRemovingFile = replaceCpy(_("Moving file %x to %y" ), L"%y", fmtFileName(custDelFolder));
+ txtRemovingDirectory = replaceCpy(_("Moving folder %x to %y" ), L"%y", fmtFileName(custDelFolder));
+ txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to %y"), L"%y", fmtFileName(custDelFolder));
break;
}
}
@@ -500,13 +477,11 @@ public:
statusHandler_ (statusHandler),
delHandling_ (delHandling),
objectsReported_(objectsReported),
- txtCreatingFile (replaceCpy(_("Creating file %x" ), L"%x", L"\"%x\"", false)),
- txtCreatingFolder(replaceCpy(_("Creating folder %x" ), L"%x", L"\"%x\"", false)),
- txtMovingFile (replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"%y\"", false)),
- txtMovingFolder (replaceCpy(replaceCpy(_("Moving folder %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"%y\"", false)) {}
+ txtMovingFile (_("Moving file %x to %y" )),
+ txtMovingFolder (_("Moving folder %x to %y")) {}
- virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) { reportStatus(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo<std::wstring>(fileTo)), fileFrom); }
- virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) { reportStatus(replaceCpy(txtMovingFolder, L"%y", utf8CvrtTo<std::wstring>(dirTo )), dirFrom ); }
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) { reportStatus(txtMovingFile, fileFrom, fileTo); }
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) { reportStatus(txtMovingFolder, dirFrom, dirTo); }
virtual void objectProcessed() //one call after each processed move
{
if (objectsReported_)
@@ -525,14 +500,15 @@ public:
}
private:
- void reportStatus(const std::wstring& rawText, const Zstring& objname) const { statusHandler_.reportStatus(replaceCpy(rawText, L"%x", utf8CvrtTo<std::wstring>(objname))); };
+ void reportStatus(const std::wstring& rawText, const Zstring& fileFrom, const Zstring& fileTo) const
+ {
+ statusHandler_.reportStatus(replaceCpy(replaceCpy(rawText, L"%x", fmtFileName(fileFrom)), L"%y", fmtFileName(fileTo)));
+ };
ProcessCallback& statusHandler_;
const DeletionHandling& delHandling_;
int* objectsReported_; //optional
- const std::wstring txtCreatingFile;
- const std::wstring txtCreatingFolder;
const std::wstring txtMovingFile;
const std::wstring txtMovingFolder;
};
@@ -553,7 +529,7 @@ struct CallbackRemoveDirImpl : public CallbackRemoveDir
private:
void processSingleObject(const Zstring& objName, const std::wstring& statusText)
{
- statusHandler_.reportStatus(replaceCpy(statusText, L"%x", utf8CvrtTo<std::wstring>(objName)));
+ statusHandler_.reportStatus(replaceCpy(statusText, L"%x", fmtFileName(objName)));
if (objectsReported_)
{
@@ -616,7 +592,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
try //... to get away cheaply!
{
- moveFile(fullName, targetFile, true, &callBack); //throw FileError
+ moveFile(fullName, targetFile, &callBack); //throw FileError
}
catch (FileError&)
{
@@ -624,10 +600,12 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
{
const Zstring targetDir = beforeLast(targetFile, FILE_NAME_SEPARATOR);
if (!dirExists(targetDir))
+ {
createDirectory(targetDir); //throw FileError
+ moveFile(fullName, targetFile, &callBack); //throw FileError -> this should work now!
+ }
else
throw;
- moveFile(fullName, targetFile, true, &callBack); //throw FileError -> this should work now!
}
}
}
@@ -696,7 +674,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
try //... to get away cheaply!
{
- moveDirectory(fullName, targetDir, true, &callBack); //throw FileError
+ moveDirectory(fullName, targetDir, &callBack); //throw FileError
}
catch (FileError&)
{
@@ -704,10 +682,12 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
{
const Zstring targetSuperDir = beforeLast(targetDir, FILE_NAME_SEPARATOR);
if (!dirExists(targetSuperDir))
+ {
createDirectory(targetSuperDir); //throw FileError
+ moveDirectory(fullName, targetDir, &callBack); //throw FileError -> this should work now!
+ }
else
throw;
- moveDirectory(fullName, targetDir, true, &callBack); //throw FileError -> this should work now!
}
}
}
@@ -859,14 +839,14 @@ public:
verifyCopiedFiles_(verifyCopiedFiles),
copyFilePermissions_(copyFilePermissions),
transactionalFileCopy_(transactionalFileCopy),
- txtCreatingFile (replaceCpy(_("Creating file %x" ), L"%x", L"\"%x\"", false)), //harmonize with duplicates in CallbackMoveFileImpl!!!
- txtCreatingLink (replaceCpy(_("Creating symbolic link %x" ), L"%x", L"\"%x\"", false)),
- txtCreatingFolder (replaceCpy(_("Creating folder %x" ), L"%x", L"\"%x\"", false)), //
- txtOverwritingFile (replaceCpy(_("Overwriting file %x" ), L"%x", L"\"%x\"", false)),
- txtOverwritingLink (replaceCpy(_("Overwriting symbolic link %x"), L"%x", L"\"%x\"", false)),
- txtVerifying (replaceCpy(_("Verifying file %x" ), L"%x", L"\"%x\"", false)),
- txtWritingAttributes(replaceCpy(_("Updating attributes of %x" ), L"%x", L"\"%x\"", false)),
- txtMovingFile (replaceCpy(replaceCpy(_("Moving file %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"%y\"", false))
+ txtCreatingFile (_("Creating file %x" )),
+ txtCreatingLink (_("Creating symbolic link %x" )),
+ txtCreatingFolder (_("Creating folder %x" )),
+ txtOverwritingFile (_("Overwriting file %x" )),
+ txtOverwritingLink (_("Overwriting symbolic link %x")),
+ txtVerifying (_("Verifying file %x" )),
+ txtWritingAttributes(_("Updating attributes of %x" )),
+ txtMovingFile (_("Moving file %x to %y"))
{}
void startSync(BaseDirMapping& baseMap)
@@ -907,8 +887,8 @@ private:
void synchronizeFolder(DirMapping& dirObj) const;
template <SelectedSide sideTrg> void synchronizeFolderInt(DirMapping& dirObj, SyncOperation syncOp) const;
- void reportInfo (const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportInfo (replaceCpy(rawText, L"%x", utf8CvrtTo<std::wstring>(objname))); };
- void reportStatus(const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportStatus(replaceCpy(rawText, L"%x", utf8CvrtTo<std::wstring>(objname))); };
+ void reportInfo (const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportInfo (replaceCpy(rawText, L"%x", fmtFileName(objname))); };
+ void reportStatus(const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportStatus(replaceCpy(rawText, L"%x", fmtFileName(objname))); };
//more low level helper
template <SelectedSide side, class DelTargetCommand>
@@ -1012,7 +992,7 @@ void SynchronizeFolderPair::prepare2StepMove(FileMapping& sourceObj,
//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", utf8CvrtTo<std::wstring>(tmpTarget)), source);
+ reportInfo(replaceCpy(txtMovingFile, L"%y", fmtFileName(tmpTarget)), source);
renameFile(source, tmpTarget); //throw FileError;
@@ -1432,7 +1412,7 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
const Zstring& source = sourceObj->getFullName<sideTrg>();
const Zstring& target = targetObj->getBaseDirPf<sideTrg>() + targetObj->getRelativeName<sideSrc>();
- reportInfo(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo<std::wstring>(target)), source);
+ reportInfo(replaceCpy(txtMovingFile, L"%y", fmtFileName(target)), source);
renameFile(source, target); //throw FileError;
@@ -1668,7 +1648,7 @@ void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperati
}
else //source deleted meanwhile...nothing was done (logical point of view!)
{
- // throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName<sideSrc>() + "\"");
+ // throw FileError
const SyncStatistics subStats(dirObj);
procCallback_.updateTotalData(-getCUD(subStats) - 1, -subStats.getDataToProcess());
@@ -1757,10 +1737,6 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
PreventStandby dummy;
(void)dummy;
-#ifdef NDEBUG
- wxLogNull noWxLogs; //prevent wxWidgets logging
-#endif
-
//PERF_START;
if (syncConfig.size() != folderCmp.size())
@@ -1770,9 +1746,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
const SyncStatistics statisticsTotal(folderCmp);
//keep at beginning so that all gui elements are initialized properly
- procCallback.initNewProcess(getCUD(statisticsTotal),
- statisticsTotal.getDataToProcess(),
- ProcessCallback::PROCESS_SYNCHRONIZING);
+ procCallback.initNewPhase(getCUD(statisticsTotal),
+ statisticsTotal.getDataToProcess(),
+ ProcessCallback::PHASE_SYNCHRONIZING);
std::deque<bool> skipFolderPair(folderCmp.size()); //folder pairs may be skipped after fatal errors were found
@@ -1930,7 +1906,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
if (!missingSrcDir.empty())
{
- procCallback.reportFatalError(_("Source directory does not exist anymore:") + L"\n\"" + missingSrcDir + L"\"");
+ procCallback.reportFatalError(replaceCpy(_("Source directory %x not found."), L"%x", fmtFileName(missingSrcDir)));
skipFolderPair[folderIndex] = true;
continue;
}
@@ -1943,13 +1919,15 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//check for sufficient free diskspace
auto checkSpace = [&](const Zstring& baseDirPf, const Int64& spaceRequired)
{
- wxLongLong freeDiskSpace;
- if (wxGetDiskSpace(toWx(baseDirPf), nullptr, &freeDiskSpace))
+ try
{
- if (0 < freeDiskSpace && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0)
- freeDiskSpace.GetValue() < spaceRequired)
- diskSpaceMissing.push_back(std::make_pair(baseDirPf, std::make_pair(spaceRequired, freeDiskSpace.GetValue())));
+ 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());
@@ -1982,14 +1960,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
std::wstring warningMessage = _("Unresolved conflicts existing!") +
L" (" + toStringSep(statisticsTotal.getConflict()) + L")\n\n";
- const SyncStatistics::ConflictTexts& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts
- for (SyncStatistics::ConflictTexts::const_iterator i = firstConflicts.begin(); i != firstConflicts.end(); ++i)
- {
- std::wstring conflictDescription = i->second;
- //conflictDescription.Replace(wxT("\n"), wxT(" ")); //remove line-breaks
-
- warningMessage += std::wstring(L"\"") + i->first + L"\": " + conflictDescription + L"\n\n";
- }
+ const auto& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts
+ for (auto iter = firstConflicts.begin(); iter != firstConflicts.end(); ++iter)
+ warningMessage += fmtFileName(iter->first) + L": " + iter->second + L"\n\n";
if (statisticsTotal.getConflict() > static_cast<int>(firstConflicts.size()))
warningMessage += L"[...]\n\n";
@@ -2000,15 +1973,15 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
}
- //check if more than 50% of total number of files/dirs are to be created/overwritten/deleted
+ //check if user accidentally selected wrong directories for sync
if (!significantDiff.empty())
{
std::wstring warningMessage = _("Significant difference detected:");
- for (DirPairList::const_iterator i = significantDiff.begin(); i != significantDiff.end(); ++i)
+ for (auto iter = significantDiff.begin(); iter != significantDiff.end(); ++iter)
warningMessage += std::wstring(L"\n\n") +
- i->first + L" <-> " + L"\n" +
- i->second;
+ iter->first + L" <-> " + L"\n" +
+ iter->second;
warningMessage += L"\n\n";
warningMessage += _("More than 50% of the total number of files will be copied or deleted!");
@@ -2023,7 +1996,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
for (auto i = diskSpaceMissing.begin(); i != diskSpaceMissing.end(); ++i)
warningMessage += std::wstring(L"\n\n") +
- L"\"" + i->first + L"\"\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);
@@ -2059,8 +2032,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
{
std::wstring warningMessage = _("A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!") + L"\n";
for (auto i = conflictDirs.begin(); i != conflictDirs.end(); ++i)
- warningMessage += std::wstring(L"\n") +
- L"\"" + *i + L"\"";
+ warningMessage += L"\n" + fmtFileName(*i);
procCallback.reportWarning(warningMessage, m_warnings.warningMultiFolderWriteAccess);
}
@@ -2095,8 +2067,8 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
makeSameLength(left, right);
const std::wstring statusTxt = _("Processing folder pair:") + L" \n" +
- L" " + left + L"\"" + j->getBaseDirPf<LEFT_SIDE >() + L"\"" + L" \n" +
- L" " + right + L"\"" + j->getBaseDirPf<RIGHT_SIDE>() + L"\"";
+ L" " + left + fmtFileName(j->getBaseDirPf<LEFT_SIDE >()) + L" \n" +
+ L" " + right + fmtFileName(j->getBaseDirPf<RIGHT_SIDE>());
procCallback.reportInfo(statusTxt);
//------------------------------------------------------------------------------------------
@@ -2158,9 +2130,6 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
guardUpdateDb.dismiss();
}
}
-
- if (!synchronizationNeeded(statisticsTotal))
- procCallback.reportInfo(_("Nothing to synchronize!")); //inform about this special case
}
catch (const std::exception& e)
{
@@ -2245,7 +2214,7 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
{
copyOperation();
}
- catch (ErrorFileLocked&)
+ catch (ErrorFileLocked& e1)
{
//if file is locked (try to) use Windows Volume Shadow Copy Service
if (!shadowCopyHandler_)
@@ -2255,9 +2224,9 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
//contains prefix: E.g. "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Program Files\FFS\sample.dat"
source = shadowCopyHandler_->makeShadowCopy(source); //throw FileError
}
- catch (const FileError& e)
+ catch (const FileError& e2)
{
- throw FileError(replaceCpy(_("Unable to copy locked file %x!"), L"%x", std::wstring(L"\"") + source + L"\"") + L"\n\n" + e.toString());
+ throw FileError(e1.toString() + L"\n\n" + e2.toString());
}
//now try again
@@ -2307,7 +2276,7 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback& c
wxFile file1(::open(source.c_str(), O_RDONLY)); //utilize UTF-8 filename
#endif
if (!file1.IsOpened())
- throw FileError(_("Error reading file:") + L" \"" + source + L"\"");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(source)));
#ifdef FFS_WIN
wxFile file2(applyLongPathPrefix(target).c_str(), wxFile::read); //don't use buffered file input for verification!
@@ -2315,27 +2284,27 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback& c
wxFile file2(::open(target.c_str(), O_RDONLY)); //utilize UTF-8 filename
#endif
if (!file2.IsOpened()) //NO cleanup necessary for (wxFile) file1
- throw FileError(_("Error reading file:") + L" \"" + target + L"\"");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(target)));
do
{
const size_t length1 = file1.Read(&memory1[0], memory1.size());
if (file1.Error())
- throw FileError(_("Error reading file:") + L" \"" + source + L"\"" + L" (r)");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(source)) + L" (r)");
callback.updateStatus(); //send progress updates
const size_t length2 = file2.Read(&memory2[0], memory2.size());
if (file2.Error())
- throw FileError(_("Error reading file:") + L" \"" + target + L"\"" + L" (r)");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(target)) + L" (r)");
callback.updateStatus(); //send progress updates
if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
- throw FileError(_("Data verification error: Source and target file have different content!") + L"\n" + L"\"" + source + L"\" -> \n\"" + target + L"\"");
+ throw FileError(_("Data verification error: Source and target file have different content!") + L"\n" + fmtFileName(source) + L" -> \n" + fmtFileName(target));
}
while (!file1.Eof());
if (!file2.Eof())
- throw FileError(_("Data verification error: Source and target file have different content!") + L"\n" + L"\"" + source + L"\" -> \n\"" + target + L"\"");
+ throw FileError(_("Data verification error: Source and target file have different content!") + L"\n" + fmtFileName(source) + L" -> \n" + fmtFileName(target));
}
@@ -2353,7 +2322,7 @@ private:
void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring& target) const
{
- procCallback_.reportInfo(replaceCpy(txtVerifying, L"%x", utf8CvrtTo<std::wstring>(target)));
+ procCallback_.reportInfo(replaceCpy(txtVerifying, L"%x", fmtFileName(target)));
VerifyStatusUpdater callback(procCallback_);
diff --git a/synchronization.h b/synchronization.h
index cbe3937d..4dcd8402 100644
--- a/synchronization.h
+++ b/synchronization.h
@@ -7,10 +7,10 @@
#ifndef SYNCHRONIZATION_H_INCLUDED
#define SYNCHRONIZATION_H_INCLUDED
+#include <zen/process_priority.h>
#include "file_hierarchy.h"
#include "lib/process_xml.h"
#include "process_callback.h"
-#include <zen/process_status.h>
namespace zen
diff --git a/ui/batch_config.cpp b/ui/batch_config.cpp
index 0ed13399..cbb667ad 100644
--- a/ui/batch_config.cpp
+++ b/ui/batch_config.cpp
@@ -33,7 +33,7 @@ class BatchDialog: public BatchDlgGenerated
friend class FolderPairCallback;
public:
- BatchDialog(wxWindow* window,
+ BatchDialog(wxWindow* parent,
const wxString& referenceFile,
const xmlAccess::XmlBatchConfig& batchCfg,
const std::shared_ptr<FolderHistory>& folderHistLeft,
@@ -42,23 +42,23 @@ public:
size_t onCompletionHistoryMax);
private:
- virtual void OnCmpSettings( wxCommandEvent& event);
- virtual void OnSyncSettings( wxCommandEvent& event);
- virtual void OnConfigureFilter( wxCommandEvent& event);
- virtual void OnHelp( wxCommandEvent& event);
+ virtual void OnCmpSettings (wxCommandEvent& event);
+ virtual void OnSyncSettings (wxCommandEvent& event);
+ virtual void OnConfigureFilter(wxCommandEvent& event);
+ virtual void OnHelp (wxCommandEvent& event);
void OnCompSettingsContext(wxCommandEvent& event);
void OnSyncSettingsContext(wxCommandEvent& event);
void OnGlobalFilterContext(wxCommandEvent& event);
- virtual void OnCheckSaveLog( wxCommandEvent& event);
+ virtual void OnCheckSaveLog (wxCommandEvent& event);
virtual void OnChangeMaxLogCountTxt(wxCommandEvent& event);
- virtual void OnClose( wxCloseEvent& event) { EndModal(0); }
- virtual void OnCancel( wxCommandEvent& event) { EndModal(0); }
- virtual void OnSaveBatchJob( wxCommandEvent& event);
- virtual void OnLoadBatchJob( wxCommandEvent& event);
- virtual void OnAddFolderPair( wxCommandEvent& event);
- virtual void OnRemoveFolderPair( wxCommandEvent& event);
- virtual void OnRemoveTopFolderPair(wxCommandEvent& event);
+ virtual void OnClose (wxCloseEvent& event) { EndModal(0); }
+ virtual void OnCancel (wxCommandEvent& event) { EndModal(0); }
+ virtual void OnSaveBatchJob (wxCommandEvent& event);
+ virtual void OnLoadBatchJob (wxCommandEvent& event);
+ virtual void OnAddFolderPair (wxCommandEvent& event);
+ virtual void OnRemoveFolderPair (wxCommandEvent& event);
+ virtual void OnRemoveTopFolderPair (wxCommandEvent& event);
void OnFilesDropped(FileDropEvent& event);
void addFolderPair(const std::vector<zen::FolderPairEnh>& newPairs, bool addFront = false);
@@ -229,14 +229,14 @@ private:
//###################################################################################################################################
-BatchDialog::BatchDialog(wxWindow* window,
+BatchDialog::BatchDialog(wxWindow* parent,
const wxString& referenceFile,
const xmlAccess::XmlBatchConfig& batchCfg,
const std::shared_ptr<FolderHistory>& folderHistLeft,
const std::shared_ptr<FolderHistory>& folderHistRight,
std::vector<std::wstring>& onCompletionHistory,
size_t onCompletionHistoryMax) :
- BatchDlgGenerated(window),
+ BatchDlgGenerated(parent),
folderHistLeft_(folderHistLeft),
folderHistRight_(folderHistRight),
onCompletionHistory_(onCompletionHistory),
@@ -317,7 +317,7 @@ void BatchDialog::OnCmpSettings(wxCommandEvent& event)
//wxPoint windowPos = m_bpButtonCmpConfig->GetScreenPosition();
//windowPos.x += m_bpButtonCmpConfig->GetSize().GetWidth() + 5;
- if (zen::showCompareCfgDialog(localBatchCfg.mainCfg.cmpConfig) == ReturnSmallDlg::BUTTON_OKAY)
+ if (zen::showCompareCfgDialog(this,localBatchCfg.mainCfg.cmpConfig) == ReturnSmallDlg::BUTTON_OKAY)
{
updateGui();
}
@@ -331,7 +331,8 @@ void BatchDialog::OnSyncSettings(wxCommandEvent& event)
onCompletionHistoryMax_
};
- if (showSyncConfigDlg(localBatchCfg.mainCfg.cmpConfig.compareVar,
+ if (showSyncConfigDlg(this,
+ localBatchCfg.mainCfg.cmpConfig.compareVar,
localBatchCfg.mainCfg.syncCfg,
nullptr,
&ewfCfg) == ReturnSyncConfig::BUTTON_OKAY) //optional input parameter
@@ -343,7 +344,8 @@ void BatchDialog::OnSyncSettings(wxCommandEvent& event)
void BatchDialog::OnConfigureFilter(wxCommandEvent& event)
{
- if (showFilterDialog(true, //is main filter dialog
+ if (showFilterDialog(this,
+ true, //is main filter dialog
localBatchCfg.mainCfg.globalFilter) == ReturnSmallDlg::BUTTON_OKAY)
{
updateGui();
@@ -455,23 +457,7 @@ void BatchDialog::OnChangeMaxLogCountTxt(wxCommandEvent& event)
void BatchDialog::OnFilesDropped(FileDropEvent& event)
{
- if (event.getFiles().empty())
- return;
-
- const std::vector<wxString>& fileList = event.getFiles();
-
- switch (xmlAccess::getMergeType(fileList)) //throw ()
- {
- case xmlAccess::MERGE_BATCH:
- case xmlAccess::MERGE_GUI:
- case xmlAccess::MERGE_GUI_BATCH:
- loadBatchFile(fileList);
- break;
-
- case xmlAccess::MERGE_OTHER:
- wxMessageBox(_("Invalid FreeFileSync config file!"), _("Error"), wxOK | wxICON_ERROR);
- break;
- }
+ loadBatchFile(event.getFiles());
}
@@ -578,11 +564,11 @@ bool BatchDialog::saveBatchFile(const wxString& filename)
//write config to XML
try
{
- xmlAccess::writeConfig(batchCfg, filename);
+ xmlAccess::writeConfig(batchCfg, toZ(filename));
}
catch (const xmlAccess::FfsXmlError& error)
{
- wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
return false;
}
@@ -611,17 +597,17 @@ void BatchDialog::loadBatchFile(const std::vector<wxString>& filenames)
try
{
//open a *.ffs_gui or *.ffs_batch file!
- xmlAccess::convertConfig(filenames, batchCfg); //throw (xmlAccess::FfsXmlError)
+ xmlAccess::convertConfig(toZ(filenames), batchCfg); //throw FfsXmlError
//xmlAccess::readConfig(filename, batchCfg);
}
catch (const xmlAccess::FfsXmlError& error)
{
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING);
+ wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
else
{
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
return;
}
}
@@ -888,70 +874,14 @@ void BatchDialog::clearAddFolderPairs()
}
-/*
-#ifdef FFS_WIN
-#include <zen/win.h> //includes "windows.h"
-#include <shlobj.h>
-#endif // FFS_WIN
-
-
-bool BatchDialog::createBatchFile(const wxString& filename)
-{
- //create shell link (instead of batch file) for full Unicode support
- HRESULT hResult = E_FAIL;
- IShellLink* pShellLink = nullptr;
-
- if (FAILED(CoCreateInstance(CLSID_ShellLink, //class identifier
- nullptr, //object isn't part of an aggregate
- CLSCTX_INPROC_SERVER, //context for running executable code
- IID_IShellLink, //interface identifier
- (void**)&pShellLink))) //pointer to storage of interface pointer
- return false;
- CleanUp<IShellLink> cleanOnExit(pShellLink);
-
- wxString freeFileSyncExe = wxStandardPaths::Get().GetExecutablePath();
- if (FAILED(pShellLink->SetPath(freeFileSyncExe.c_str())))
- return false;
-
- if (FAILED(pShellLink->SetArguments(getCommandlineArguments().c_str())))
- return false;
-
- if (FAILED(pShellLink->SetIconLocation(freeFileSyncExe.c_str(), 1))) //second icon from executable file is used
- return false;
-
- if (FAILED(pShellLink->SetDescription(_("FreeFileSync Batch Job"))))
- return false;
-
- IPersistFile* pPersistFile = nullptr;
- if (FAILED(pShellLink->QueryInterface(IID_IPersistFile, (void**)&pPersistFile)))
- return false;
- CleanUp<IPersistFile> cleanOnExit2(pPersistFile);
-
- //pPersistFile->Save accepts unicode input only
-#ifdef _UNICODE
- hResult = pPersistFile->Save(filename.c_str(), TRUE);
-#else
- WCHAR wszTemp [MAX_PATH];
- if (MultiByteToWideChar(CP_ACP, 0, filename.c_str(), -1, wszTemp, MAX_PATH) == 0)
- return false;
-
- hResult = pPersistFile->Save(wszTemp, TRUE);
-#endif
- if (FAILED(hResult))
- return false;
-
- return true;
-}
-*/
-
-
-void zen::showSyncBatchDlg(const wxString& referenceFile,
+void zen::showSyncBatchDlg(wxWindow* parent,
+ const wxString& referenceFile,
const xmlAccess::XmlBatchConfig& batchCfg,
const std::shared_ptr<FolderHistory>& folderHistLeft,
const std::shared_ptr<FolderHistory>& folderHistRight,
std::vector<std::wstring>& execFinishedhistory,
size_t execFinishedhistoryMax)
{
- BatchDialog batchDlg(nullptr, referenceFile, batchCfg, folderHistLeft, folderHistRight, execFinishedhistory, execFinishedhistoryMax);
+ BatchDialog batchDlg(parent, referenceFile, batchCfg, folderHistLeft, folderHistRight, execFinishedhistory, execFinishedhistoryMax);
batchDlg.ShowModal();
}
diff --git a/ui/batch_config.h b/ui/batch_config.h
index 472f21bf..04f0bf04 100644
--- a/ui/batch_config.h
+++ b/ui/batch_config.h
@@ -10,9 +10,11 @@
#include "../lib/process_xml.h"
#include "folder_history_box.h"
+
namespace zen
{
-void showSyncBatchDlg(const wxString& referenceFile,
+void showSyncBatchDlg(wxWindow* parent,
+ const wxString& referenceFile,
const xmlAccess::XmlBatchConfig& batchCfg,
const std::shared_ptr<FolderHistory>& folderHistLeft,
const std::shared_ptr<FolderHistory>& folderHistRight,
@@ -20,5 +22,4 @@ void showSyncBatchDlg(const wxString& referenceFile,
size_t execFinishedhistoryMax);
}
-
#endif // BATCHCONFIG_H_INCLUDED
diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp
index 0c45db3f..7254f570 100644
--- a/ui/batch_status_handler.cpp
+++ b/ui/batch_status_handler.cpp
@@ -5,18 +5,17 @@
// **************************************************************************
#include "batch_status_handler.h"
-#include "msg_popup.h"
#include <wx/ffile.h>
-#include <wx/msgdlg.h>
-#include "../lib/ffs_paths.h"
#include <zen/file_handling.h>
-#include "../lib/resolve_path.h"
+#include <zen/file_traverser.h>
#include <wx+/string_conv.h>
#include <wx+/app_main.h>
-#include <zen/file_traverser.h>
-#include <zen/time.h>
-#include "exec_finished_box.h"
+#include <wx+/format_unit.h>
#include <wx+/shell_execute.h>
+#include "msg_popup.h"
+#include "exec_finished_box.h"
+#include "../lib/ffs_paths.h"
+#include "../lib/resolve_path.h"
#include "../lib/status_handler_impl.h"
using namespace zen;
@@ -24,7 +23,7 @@ using namespace zen;
namespace
{
-class FindLogfiles : public zen::TraverseCallback
+class FindLogfiles : public TraverseCallback
{
public:
FindLogfiles(const Zstring& prefix, std::vector<Zstring>& logfiles) : prefix_(prefix), logfiles_(logfiles) {}
@@ -57,31 +56,47 @@ public:
{
logFile.Open(toWx(logfileName), L"w");
if (!logFile.IsOpened())
- throw FileError(_("Unable to create log file!") + L"\"" + logfileName + L"\"");
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(logfileName)));
//write header
- wxString headerLine = wxString(L"FreeFileSync - ") + _("Batch execution") + L" - " + formatTime<wxString>(FORMAT_DATE);
-
- logFile.Write(headerLine + wxChar('\n'));
+ 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');
- logItemStart = formatTime<wxString>(L"[%X] ") + _("Start");
+ //logItemStart = formatTime<wxString>(L"[%X] ") + _("Start");
totalTime.Start(); //measure total time
}
- void writeLog(const ErrorLog& log, const std::wstring& finalStatus)
+ void writeLog(const ErrorLog& log, const std::wstring& finalStatus,
+ int itemsSynced, Int64 dataSynced,
+ int itemsTotal, Int64 dataTotal)
{
- const size_t sepLineLen = finalStatus.size();
+ //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" " + toStringSep(itemsSynced) + L" (" + filesizeToShortString(dataSynced) + L")");
+
+ if (itemsSynced != itemsTotal ||
+ dataSynced != dataTotal)
+ results.push_back(L" " + _("Items remaining:") + L" " + toStringSep(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()); });
- //result + statistics
- logFile.Write(wxString().Pad(sepLineLen, L'_') + L'\n');
- logFile.Write(L"\n" + finalStatus + L"\n");
+ 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");
- logFile.Write(logItemStart + L"\n\n");
+ //logFile.Write(logItemStart + L"\n\n");
- //write actual logfile
+ //write log items
const auto& entries = log.getEntries();
for (auto iter = entries.begin(); iter != entries.end(); ++iter)
{
@@ -90,9 +105,9 @@ public:
logFile.Write(L'\n');
}
- //write footer
- logFile.Write(L'\n');
- logFile.Write(formatTime<wxString>(L"[%X] ") + _("Stop") + L" (" + _("Total time:") + L" " + wxTimeSpan::Milliseconds(totalTime.Time()).Format() + L")\n");
+ ////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()
@@ -111,7 +126,7 @@ public:
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 { zen::removeFile(filename); } catch (FileError&) {} });
+ [](const Zstring& filename) { try { removeFile(filename); } catch (FileError&) {} });
}
//Zstring getLogfileName() const { return logfileName; }
@@ -121,23 +136,20 @@ private:
{
//create logfile directory
Zstring logfileDir = logfileDirectory.empty() ?
- zen::getConfigDir() + Zstr("Logs") :
- zen::getFormattedDirectoryName(logfileDirectory);
+ getConfigDir() + Zstr("Logs") :
+ getFormattedDirectoryName(logfileDirectory);
- if (!zen::dirExists(logfileDir))
- zen::createDirectory(logfileDir); //throw FileError; create recursively if necessary
+ if (!dirExists(logfileDir))
+ createDirectory(logfileDir); //throw FileError; create recursively if necessary
//assemble logfile name
- if (!endsWith(logfileDir, FILE_NAME_SEPARATOR))
- logfileDir += FILE_NAME_SEPARATOR;
-
- const Zstring logfileName = logfileDir + toZ(jobName) + Zstr(" ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"));
+ const Zstring logfileName = appendSeparator(logfileDir) + toZ(jobName) + Zstr(" ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"));
//ensure uniqueness
Zstring output = logfileName + Zstr(".log");
- for (int i = 1; zen::somethingExists(output); ++i)
- output = logfileName + Zstr('_') + zen::numberTo<Zstring>(i) + Zstr(".log");
+ for (int i = 1; somethingExists(output); ++i)
+ output = logfileName + Zstr('_') + numberTo<Zstring>(i) + Zstr(".log");
return output;
}
@@ -145,7 +157,6 @@ private:
const Zstring logfileName;
wxFFile logFile;
wxStopWatch totalTime;
- wxString logItemStart;
};
@@ -163,21 +174,18 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
showFinalResults(showProgress), //=> exit immediately or wait when finished
switchToGuiRequested(false),
handleError_(handleError),
- currentProcess(StatusHandler::PROCESS_NONE),
returnValue(returnVal),
- syncStatusFrame(*this, nullptr, SyncStatus::SCANNING, showProgress, jobName, execWhenFinished, execFinishedHistory)
+ syncStatusFrame(*this, *this, nullptr, showProgress, jobName, execWhenFinished, execFinishedHistory)
{
- if (logFileCountMax > 0)
- {
+ if (logFileCountMax > 0) //init log file: starts internal timer!
if (!tryReportingError([&]
{
- logFile = std::make_shared<LogFile>(toZ(logfileDirectory), jobName); //throw FileError
+ logFile.reset(new LogFile(toZ(logfileDirectory), jobName)); //throw FileError
logFile->limitLogfileCount(logFileCountMax); //throw()
}, *this))
- {
- returnValue = -7;
- throw BatchAbortProcess();
- }
+ {
+ returnValue = -7;
+ throw BatchAbortProcess();
}
//::wxSetEnv(L"logfile", logFile->getLogfileName());
@@ -194,7 +202,7 @@ BatchStatusHandler::~BatchStatusHandler()
{
returnValue = -4;
finalStatus = _("Synchronization aborted!");
- errorLog.logMsg(finalStatus, TYPE_FATAL_ERROR);
+ errorLog.logMsg(finalStatus, TYPE_ERROR);
}
else if (totalErrors > 0)
{
@@ -204,14 +212,20 @@ BatchStatusHandler::~BatchStatusHandler()
}
else
{
- finalStatus = _("Synchronization completed successfully!");
+ if (getObjectsTotal(PHASE_SYNCHRONIZING) == 0 && //we're past "initNewPhase(PHASE_SYNCHRONIZING)" at this point!
+ getDataTotal (PHASE_SYNCHRONIZING) == 0)
+ finalStatus = _("Nothing to synchronize!"); //even if "ignored conflicts" occurred!
+ else
+ finalStatus = _("Synchronization completed successfully!");
errorLog.logMsg(finalStatus, TYPE_INFO);
}
//print the results list: logfile
if (logFile.get())
{
- logFile->writeLog(errorLog, finalStatus);
+ logFile->writeLog(errorLog, finalStatus,
+ getObjectsCurrent(PHASE_SYNCHRONIZING), getDataCurrent(PHASE_SYNCHRONIZING),
+ getObjectsTotal (PHASE_SYNCHRONIZING), getDataTotal (PHASE_SYNCHRONIZING));
logFile.reset(); //close file now: user may do something with it in "on completion"
}
@@ -240,19 +254,18 @@ BatchStatusHandler::~BatchStatusHandler()
shellExecute(finalCommand);
}
-
if (showFinalResults) //warning: wxWindow::Show() is called within processHasFinished()!
{
//notify about (logical) application main window => program won't quit, but stay on this dialog
- zen::setMainWindow(syncStatusFrame.getAsWindow());
+ setMainWindow(syncStatusFrame.getAsWindow());
//notify to syncStatusFrame that current process has ended
if (abortIsRequested())
- syncStatusFrame.processHasFinished(SyncStatus::ABORTED, errorLog); //enable okay and close events
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_ABORTED, errorLog); //enable okay and close events
else if (totalErrors > 0)
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_ERROR, errorLog);
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_FINISHED_WITH_ERROR, errorLog);
else
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS, errorLog);
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_FINISHED_WITH_SUCCESS, errorLog);
}
else
syncStatusFrame.closeWindowDirectly(); //syncStatusFrame is main window => program will quit directly
@@ -260,68 +273,36 @@ BatchStatusHandler::~BatchStatusHandler()
}
-void BatchStatusHandler::initNewProcess(int objectsTotal, zen::Int64 dataTotal, StatusHandler::Process processID)
+void BatchStatusHandler::initNewPhase(int objectsTotal, Int64 dataTotal, ProcessCallback::Phase phaseID)
{
- currentProcess = processID;
-
- switch (currentProcess)
- {
- case StatusHandler::PROCESS_SCANNING:
- syncStatusFrame.initNewProcess(SyncStatus::SCANNING, 0, 0); //initialize some gui elements (remaining time, speed)
- break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- syncStatusFrame.initNewProcess(SyncStatus::COMPARING_CONTENT, objectsTotal, dataTotal);
- break;
- case StatusHandler::PROCESS_SYNCHRONIZING:
- syncStatusFrame.initNewProcess(SyncStatus::SYNCHRONIZING, objectsTotal, dataTotal);
- break;
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
- }
+ StatusHandler::initNewPhase(objectsTotal, dataTotal, phaseID);
+ syncStatusFrame.initNewPhase(); //call after "StatusHandler::initNewPhase"
}
void BatchStatusHandler::updateProcessedData(int objectsDelta, Int64 dataDelta)
{
- switch (currentProcess)
+ StatusHandler::updateProcessedData(objectsDelta, dataDelta);
+
+ switch (currentPhase())
{
- case StatusHandler::PROCESS_SCANNING:
- syncStatusFrame.incScannedObjects_NoUpdate(objectsDelta); //throw ()
- break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- case StatusHandler::PROCESS_SYNCHRONIZING:
- syncStatusFrame.incProcessedData_NoUpdate(objectsDelta, dataDelta);
- break;
- case StatusHandler::PROCESS_NONE:
+ case ProcessCallback::PHASE_NONE:
assert(false);
+ case ProcessCallback::PHASE_SCANNING:
+ break;
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ syncStatusFrame.reportCurrentBytes(getDataCurrent(currentPhase()));
break;
}
-
//note: this method should NOT throw in order to properly allow undoing setting of statistics!
}
-void BatchStatusHandler::updateTotalData(int objectsDelta, Int64 dataDelta)
-{
- assert(currentProcess != PROCESS_SCANNING);
- syncStatusFrame.incTotalData_NoUpdate(objectsDelta, dataDelta);
-}
-
-
-void BatchStatusHandler::reportStatus(const std::wstring& text)
-{
- syncStatusFrame.setStatusText_NoUpdate(text);
- requestUiRefresh(); //throw AbortThisProcess
-}
-
-
void BatchStatusHandler::reportInfo(const std::wstring& text)
{
+ StatusHandler::reportInfo(text);
errorLog.logMsg(text, TYPE_INFO);
-
- syncStatusFrame.setStatusText_NoUpdate(text);
- requestUiRefresh(); //throw AbortThisProcess
}
@@ -340,8 +321,9 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
forceUiRefresh();
bool dontWarnAgain = false;
- switch (showWarningDlg(ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_SWITCH | ReturnWarningDlg::BUTTON_ABORT,
- warningMessage + wxT("\n\n") + _("Press \"Switch\" to open FreeFileSync GUI mode."),
+ switch (showWarningDlg(syncStatusFrame.getAsWindow(),
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_SWITCH | ReturnWarningDlg::BUTTON_ABORT,
+ warningMessage + L"\n\n" + _("Press \"Switch\" to resolve issues in FreeFileSync main dialog."),
dontWarnAgain))
{
case ReturnWarningDlg::BUTTON_ABORT:
@@ -349,7 +331,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
break;
case ReturnWarningDlg::BUTTON_SWITCH:
- errorLog.logMsg(_("Switching to FreeFileSync GUI mode..."), TYPE_INFO);
+ errorLog.logMsg(_("Switching to FreeFileSync main dialog..."), TYPE_INFO);
switchToGuiRequested = true;
abortThisProcess();
break;
@@ -365,7 +347,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
abortThisProcess();
break;
- case xmlAccess::ON_ERROR_IGNORE: //no unhandled error situation!
+ case xmlAccess::ON_ERROR_IGNORE:
break;
}
}
@@ -381,9 +363,9 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
- errorMessage,
- &ignoreNextErrors))
+ switch (showErrorDlg(syncStatusFrame.getAsWindow(),
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
if (ignoreNextErrors) //falsify only
@@ -428,9 +410,9 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
- errorMessage,
- &ignoreNextErrors))
+ switch (showErrorDlg(syncStatusFrame.getAsWindow(),
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
+ errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
if (ignoreNextErrors) //falsify only
@@ -459,12 +441,12 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
void BatchStatusHandler::forceUiRefresh()
{
- syncStatusFrame.updateStatusDialogNow();
+ syncStatusFrame.updateProgress();
}
void BatchStatusHandler::abortThisProcess()
{
- requestAbortion();
+ requestAbortion(); //just make sure...
throw BatchAbortProcess(); //abort can be triggered by syncStatusFrame
}
diff --git a/ui/batch_status_handler.h b/ui/batch_status_handler.h
index 0657e881..cc23019e 100644
--- a/ui/batch_status_handler.h
+++ b/ui/batch_status_handler.h
@@ -14,13 +14,12 @@
#include "switch_to_gui.h"
class LogFile;
-class SyncStatus;
//Exception class used to abort the "compare" and "sync" process
class BatchAbortProcess {};
-class BatchStatusHandler : public StatusHandler
+class BatchStatusHandler : public zen::StatusHandler
{
public:
BatchStatusHandler(bool showProgress, //defines: -start minimized and -quit immediately when finished
@@ -34,10 +33,8 @@ public:
std::vector<std::wstring>& execFinishedHistory);
~BatchStatusHandler();
- virtual void initNewProcess (int objectsTotal, zen::Int64 dataTotal, Process processID);
+ virtual void initNewPhase (int objectsTotal, zen::Int64 dataTotal, Phase phaseID);
virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta);
- virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta);
- virtual void reportStatus(const std::wstring& text);
virtual void reportInfo(const std::wstring& text);
virtual void forceUiRefresh();
@@ -46,18 +43,17 @@ public:
virtual void reportFatalError(const std::wstring& errorMessage);
private:
- virtual void abortThisProcess();
+ virtual void abortThisProcess(); //throw BatchAbortProcess
const zen::SwitchToGui& switchBatchToGui_; //functionality to change from batch mode to GUI mode
bool showFinalResults;
bool switchToGuiRequested;
xmlAccess::OnError handleError_;
zen::ErrorLog errorLog; //list of non-resolved errors and warnings
- Process currentProcess;
int& returnValue;
SyncStatus syncStatusFrame; //the window managed by SyncStatus has longer lifetime than this handler!
- std::shared_ptr<LogFile> logFile; //optional!
+ std::unique_ptr<LogFile> logFile; //optional!
};
diff --git a/ui/check_version.cpp b/ui/check_version.cpp
index ba922f97..37fa16ff 100644
--- a/ui/check_version.cpp
+++ b/ui/check_version.cpp
@@ -82,27 +82,30 @@ bool newerVersionExists(const wxString& onlineVersion)
}
-void zen::checkForUpdateNow()
+void zen::checkForUpdateNow(wxWindow* parent)
{
wxString onlineVersion;
if (!getOnlineVersion(onlineVersion))
{
- wxMessageBox(_("Unable to connect to sourceforge.net!"), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(_("Unable to connect to sourceforge.net!"), _("Error"), wxOK | wxICON_ERROR, parent);
return;
}
if (newerVersionExists(onlineVersion))
{
- const int rv = wxMessageBox(wxString(_("A newer version of FreeFileSync is available:")) + wxT(" v") + onlineVersion + wxT(". ") + _("Download now?"), _("Information"), wxYES_NO | wxICON_QUESTION);
+ const int rv = wxMessageBox(_("A newer version of FreeFileSync is available:") + L" v" + onlineVersion + L". " + _("Download now?"),
+ _("Information"),
+ wxYES_NO | wxICON_QUESTION,
+ parent);
if (rv == wxYES)
wxLaunchDefaultBrowser(wxString(L"http://sourceforge.net/projects/freefilesync/files/freefilesync/v") + onlineVersion + L"/");
}
else
- wxMessageBox(_("FreeFileSync is up to date!"), _("Information"), wxICON_INFORMATION);
+ wxMessageBox(_("FreeFileSync is up to date!"), _("Information"), wxICON_INFORMATION, parent);
}
-void zen::checkForUpdatePeriodically(long& lastUpdateCheck)
+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
@@ -113,14 +116,14 @@ void zen::checkForUpdatePeriodically(long& lastUpdateCheck)
{
if (lastUpdateCheck == 0)
{
- const bool checkRegularly = showQuestionDlg(ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO,
+ const bool checkRegularly = showQuestionDlg(parent, ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO,
_("Do you want FreeFileSync to automatically check for updates every week?") + L"\n" +
_("(Requires an Internet connection!)")) == ReturnQuestionDlg::BUTTON_YES;
if (checkRegularly)
{
lastUpdateCheck = 123; //some old date (few seconds after 1970)
- checkForUpdatePeriodically(lastUpdateCheck); //check for updates now
+ checkForUpdatePeriodically(parent, lastUpdateCheck); //check for updates now
}
else
lastUpdateCheck = -1; //don't check for updates anymore
@@ -135,7 +138,10 @@ void zen::checkForUpdatePeriodically(long& lastUpdateCheck)
if (newerVersionExists(onlineVersion))
{
- const int rv = wxMessageBox(wxString(_("A newer version of FreeFileSync is available:")) + wxT(" v") + onlineVersion + wxT(". ") + _("Download now?"), _("Information"), wxYES_NO | wxICON_QUESTION);
+ const int rv = wxMessageBox(_("A newer version of FreeFileSync is available:") + L" v" + onlineVersion + L". " + _("Download now?"),
+ _("Information"),
+ wxYES_NO | wxICON_QUESTION,
+ parent);
if (rv == wxYES)
wxLaunchDefaultBrowser(wxString(L"http://sourceforge.net/projects/freefilesync/files/freefilesync/v") + onlineVersion + L"/");
}
diff --git a/ui/check_version.h b/ui/check_version.h
index bbf8d7cb..5a0bbd73 100644
--- a/ui/check_version.h
+++ b/ui/check_version.h
@@ -7,12 +7,14 @@
#ifndef UPDATEVERSION_H_INCLUDED
#define UPDATEVERSION_H_INCLUDED
+#include <wx/window.h>
+
namespace zen
{
-void checkForUpdateNow();
+void checkForUpdateNow(wxWindow* parent);
-void checkForUpdatePeriodically(long& lastUpdateCheck);
+void checkForUpdatePeriodically(wxWindow* parent, long& lastUpdateCheck);
}
#endif // UPDATEVERSION_H_INCLUDED
diff --git a/ui/custom_grid.cpp b/ui/custom_grid.cpp
index 465a1b6f..fdb72161 100644
--- a/ui/custom_grid.cpp
+++ b/ui/custom_grid.cpp
@@ -91,6 +91,12 @@ std::pair<ptrdiff_t, ptrdiff_t> getVisibleRows(Grid& grid) //returns range [from
}
+Zstring getExtension(const Zstring& shortName)
+{
+ return contains(shortName, Zchar('.')) ? afterLast(shortName, Zchar('.')) : Zstring();
+};
+
+
class IconUpdater;
class GridEventManager;
@@ -121,7 +127,6 @@ private:
Grid& grid_;
};
-
//########################################################################################################
template <SelectedSide side>
@@ -254,6 +259,7 @@ private:
struct GetTextValue : public FSObjectVisitor
{
GetTextValue(ColumnTypeRim colType, const FileSystemObject& fso) : colType_(colType), fsObj_(fso) {}
+
virtual void visit(const FileMapping& fileObj)
{
switch (colType_)
@@ -279,7 +285,7 @@ private:
value = zen::utcToLocalTimeString(fileObj.getLastWriteTime<side>());
break;
case COL_TYPE_EXTENSION: //file extension
- value = toWx(fileObj.getExtension<side>());
+ value = toWx(getExtension(fileObj.getShortName<side>()));
break;
}
}
@@ -309,7 +315,7 @@ private:
value = zen::utcToLocalTimeString(linkObj.getLastWriteTime<side>());
break;
case COL_TYPE_EXTENSION: //file extension
- value = wxEmptyString;
+ value = toWx(getExtension(linkObj.getShortName<side>()));
break;
}
}
@@ -543,30 +549,32 @@ private:
virtual wxString getToolTip(size_t row, ColumnType colType) const
{
wxString toolTip;
+
const FileSystemObject* fsObj = getRawData(row);
if (fsObj && !fsObj->isEmpty<side>())
{
+ toolTip = toWx(gridDataView_->getFolderPairCount() > 1 ? //gridDataView_ bound in this path
+ fsObj->getFullName<side>() :
+ fsObj->getRelativeName<side>());
+
struct AssembleTooltip : public FSObjectVisitor
{
AssembleTooltip(wxString& tipMsg) : tipMsg_(tipMsg) {}
virtual void visit(const FileMapping& fileObj)
{
- tipMsg_ = copyStringTo<wxString>(std::wstring() + fileObj.getRelativeName<side>() + L"\n" +
- _("Size") + L": " + zen::filesizeToShortString(to<Int64>(fileObj.getFileSize<side>())) + L"\n" +
- _("Date") + L": " + zen::utcToLocalTimeString(fileObj.getLastWriteTime<side>()));
+ tipMsg_ += L"\n" +
+ _("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_ = copyStringTo<wxString>(std::wstring() + linkObj.getRelativeName<side>() + L"\n" +
- _("Date") + L": " + zen::utcToLocalTimeString(linkObj.getLastWriteTime<side>()));
+ tipMsg_ += L"\n" +
+ _("Date") + L": " + zen::utcToLocalTimeString(linkObj.getLastWriteTime<side>());
}
- virtual void visit(const DirMapping& dirObj)
- {
- tipMsg_ = toWx(dirObj.getRelativeName<side>());
- }
+ virtual void visit(const DirMapping& dirObj) {}
wxString& tipMsg_;
} assembler(toolTip);
@@ -700,7 +708,7 @@ public:
{
case BLOCKPOS_CHECK_BOX:
{
- const FileSystemObject* fsObj = getRawData(rowFrom);
+ const FileSystemObject* fsObj = getRawData(dragSelection->first);
const bool setIncluded = fsObj ? !fsObj->isActive() : true;
CheckRowsEvent evt(rowFrom, rowTo, setIncluded);
diff --git a/ui/exec_finished_box.cpp b/ui/exec_finished_box.cpp
index a8ee9f4a..edc57d58 100644
--- a/ui/exec_finished_box.cpp
+++ b/ui/exec_finished_box.cpp
@@ -192,7 +192,8 @@ void ExecFinishedBox::setValueAndUpdateList(const std::wstring& value)
void ExecFinishedBox::OnSelection(wxCommandEvent& event)
{
wxCommandEvent dummy2(wxEVT_REPLACE_BUILT_IN_COMMANDS); //we cannot replace built-in commands at this position in call stack, so defer to a later time!
- GetEventHandler()->AddPendingEvent(dummy2); //
+ if (auto handler = GetEventHandler())
+ handler->AddPendingEvent(dummy2);
event.Skip();
}
diff --git a/ui/folder_history_box.cpp b/ui/folder_history_box.cpp
index 76ed785e..72204c3a 100644
--- a/ui/folder_history_box.cpp
+++ b/ui/folder_history_box.cpp
@@ -146,18 +146,12 @@ void FolderHistoryBox::OnMouseWheel(wxMouseEvent& event)
//redirect to parent scrolled window!
wxWindow* wnd = this;
- for (;;)
- {
- wnd = wnd->GetParent();
- if (!wnd)
- break;
-
+ while ((wnd = wnd->GetParent()) != nullptr) //silence MSVC warning
if (dynamic_cast<wxScrolledWindow*>(wnd) != nullptr)
{
wnd->GetEventHandler()->AddPendingEvent(event);
break;
}
- }
// event.Skip();
}
diff --git a/ui/folder_pair.h b/ui/folder_pair.h
index 7b1e7643..d80d8a05 100644
--- a/ui/folder_pair.h
+++ b/ui/folder_pair.h
@@ -151,7 +151,7 @@ private:
CompConfig cmpCfg = altCompConfig.get() ? *altCompConfig : mainCfg.cmpConfig;
- if (showCompareCfgDialog(cmpCfg) == ReturnSmallDlg::BUTTON_OKAY)
+ if (showCompareCfgDialog(getParentWindow(), cmpCfg) == ReturnSmallDlg::BUTTON_OKAY)
{
altCompConfig = std::make_shared<CompConfig>(cmpCfg);
refreshButtons();
@@ -167,7 +167,8 @@ private:
CompConfig cmpCfg = altCompConfig.get() ? *altCompConfig : mainCfg.cmpConfig;
SyncConfig syncCfg = altSyncConfig.get() ? *altSyncConfig : mainCfg.syncCfg;
- if (showSyncConfigDlg(cmpCfg.compareVar,
+ if (showSyncConfigDlg(getParentWindow(),
+ cmpCfg.compareVar,
syncCfg,
nullptr,
nullptr) == ReturnSyncConfig::BUTTON_OKAY) //optional input parameter
@@ -183,7 +184,8 @@ private:
{
FilterConfig localFiltTmp = localFilter;
- if (showFilterDialog(false, //is local filter dialog
+ if (showFilterDialog(getParentWindow(),
+ false, //is local filter dialog
localFiltTmp) == ReturnSmallDlg::BUTTON_OKAY)
{
localFilter = localFiltTmp;
diff --git a/ui/grid_view.cpp b/ui/grid_view.cpp
index 2a3e84e3..80ff895c 100644
--- a/ui/grid_view.cpp
+++ b/ui/grid_view.cpp
@@ -267,10 +267,9 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map
}
-void GridView::getAllFileRef(const std::set<size_t>& rows, std::vector<FileSystemObject*>& output)
+std::vector<FileSystemObject*> GridView::getAllFileRef(const std::set<size_t>& rows)
{
- output.clear();
- output.reserve(rows.size());
+ std::vector<FileSystemObject*> output;
auto iterLast = rows.lower_bound(rowsOnView()); //loop over valid rows only!
std::for_each(rows.begin(), iterLast,
@@ -279,6 +278,7 @@ void GridView::getAllFileRef(const std::set<size_t>& rows, std::vector<FileSyste
if (FileSystemObject* fsObj = FileSystemObject::retrieve(viewRef[pos]))
output.push_back(fsObj);
});
+ return output;
}
@@ -336,6 +336,13 @@ void GridView::setData(FolderComparison& folderCmp)
std::vector<RefIndex>().swap(sortedRef); //
currentSort.reset();
+ folderPairCount = std::count_if(begin(folderCmp), end(folderCmp),
+ [](const BaseDirMapping& baseObj) //count non-empty pairs to distinguish single/multiple folder pair cases
+ {
+ return !baseObj.getBaseDirPf<LEFT_SIDE >().empty() ||
+ !baseObj.getBaseDirPf<RIGHT_SIDE>().empty();
+ });
+
for (auto iter = begin(folderCmp); iter != end(folderCmp); ++iter)
SerializeHierarchy(sortedRef, iter - begin(folderCmp)).execute(*iter);
}
@@ -499,7 +506,7 @@ void GridView::sortView(ColumnTypeRim type, bool onLeft, bool ascending)
viewRef.clear();
rowPositions.clear();
rowPositionsFirstChild.clear();
- currentSort.reset(new SortInfo(type, onLeft, ascending));
+ currentSort = make_unique<SortInfo>(type, onLeft, ascending);
switch (type)
{
diff --git a/ui/grid_view.h b/ui/grid_view.h
index fc828f91..c830224b 100644
--- a/ui/grid_view.h
+++ b/ui/grid_view.h
@@ -18,6 +18,8 @@ namespace zen
class GridView
{
public:
+ GridView() : folderPairCount(0) {}
+
//direct data access via row number
const FileSystemObject* getObject(size_t row) const; //returns nullptr if object is not found; complexity: constant!
/**/
@@ -26,7 +28,7 @@ public:
size_t rowsTotal () const { return sortedRef.size(); } //total rows available
//get references to FileSystemObject: no nullptr-check needed! Everything's bound.
- void getAllFileRef(const std::set<size_t>& rows, std::vector<FileSystemObject*>& output);
+ std::vector<FileSystemObject*> getAllFileRef(const std::set<size_t>& rows);
struct StatusCmpResult
{
@@ -115,6 +117,8 @@ public:
ptrdiff_t findRowFirstChild(const HierarchyObject* hierObj) const; // find first child of DirMapping or BaseDirMapping *on sorted sub view*
//"hierObj" may be invalid, it is NOT dereferenced, return < 0 if not found
+ size_t getFolderPairCount() const { return folderPairCount; } //count non-empty pairs to distinguish single/multiple folder pair cases
+
private:
struct RefIndex
{
@@ -129,8 +133,8 @@ private:
zen::hash_map<FileSystemObject::ObjectIdConst, size_t> rowPositions; //find row positions on sortedRef directly
- zen::hash_map<const HierarchyObject*, size_t> rowPositionsFirstChild; //find first child on sortedRef of a hierarchy object
- //NEVER DEREFERENCE HierarchyObject*!!! lookup only!
+ zen::hash_map<const void*, size_t> rowPositionsFirstChild; //find first child on sortedRef of a hierarchy object
+ //void* instead of HierarchyObject*: these are weak pointers and should *never be dereferenced*!
std::vector<FileSystemObject::ObjectId> viewRef; //partial view on sortedRef
/* /|\
@@ -141,6 +145,8 @@ private:
| (setData...)
| */
//std::shared_ptr<FolderComparison> folderCmp; //actual comparison data: owned by GridView!
+ size_t folderPairCount; //number of non-empty folder pairs
+
class SerializeHierarchy;
diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp
index 9caa466a..4c42caf1 100644
--- a/ui/gui_generated.cpp
+++ b/ui/gui_generated.cpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Mar 17 2012)
+// C++ code generated with wxFormBuilder (version Apr 10 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@@ -928,23 +928,11 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id,
bSizer154->Add( m_staticTextFilesRemaining, 0, wxALIGN_BOTTOM, 5 );
- m_staticText117 = new wxStaticText( this, wxID_ANY, _("("), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText117->Wrap( -1 );
- m_staticText117->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer154->Add( m_staticText117, 0, wxLEFT|wxALIGN_BOTTOM, 5 );
-
m_staticTextDataRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDataRemaining->Wrap( -1 );
m_staticTextDataRemaining->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
- bSizer154->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM, 5 );
-
- m_staticText118 = new wxStaticText( this, wxID_ANY, _(")"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText118->Wrap( -1 );
- m_staticText118->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer154->Add( m_staticText118, 0, wxALIGN_BOTTOM, 5 );
+ bSizer154->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM|wxLEFT, 5 );
bSizerFilesRemaining->Add( bSizer154, 0, wxALIGN_BOTTOM|wxLEFT, 5 );
@@ -1413,7 +1401,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer68->Add( m_buttonLoad, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- m_button6 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button6 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button6->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer68->Add( m_button6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -1881,13 +1869,13 @@ SyncCfgDlgGenerated::SyncCfgDlgGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer291;
bSizer291 = new wxBoxSizer( wxHORIZONTAL );
- m_buttonOK = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonOK->SetDefault();
m_buttonOK->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer291->Add( m_buttonOK, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
- m_button16 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button16 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button16->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer291->Add( m_button16, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -2042,13 +2030,13 @@ CmpCfgDlgGenerated::CmpCfgDlgGenerated( wxWindow* parent, wxWindowID id, const w
wxBoxSizer* bSizer22;
bSizer22 = new wxBoxSizer( wxHORIZONTAL );
- m_button10 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button10 = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button10->SetDefault();
m_button10->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer22->Add( m_button10, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
- m_button6 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button6 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button6->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer22->Add( m_button6, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -2064,6 +2052,8 @@ CmpCfgDlgGenerated::CmpCfgDlgGenerated( wxWindow* parent, wxWindowID id, const w
this->Layout();
bSizer136->Fit( this );
+ this->Centre( wxBOTH );
+
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CmpCfgDlgGenerated::OnClose ) );
m_radioBtnSizeDate->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( CmpCfgDlgGenerated::OnTimeSize ), NULL, this );
@@ -2168,23 +2158,11 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
bSizerItemsProc->Add( m_staticTextProcessedObj, 0, wxALIGN_BOTTOM, 5 );
- m_staticText98 = new wxStaticText( m_panelProgress, wxID_ANY, _("("), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText98->Wrap( -1 );
- m_staticText98->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizerItemsProc->Add( m_staticText98, 0, wxLEFT|wxALIGN_BOTTOM, 5 );
-
m_staticTextDataProcessed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDataProcessed->Wrap( -1 );
m_staticTextDataProcessed->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
- bSizerItemsProc->Add( m_staticTextDataProcessed, 0, wxALIGN_BOTTOM, 5 );
-
- m_staticText99 = new wxStaticText( m_panelProgress, wxID_ANY, _(")"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText99->Wrap( -1 );
- m_staticText99->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizerItemsProc->Add( m_staticText99, 0, wxALIGN_BOTTOM, 5 );
+ bSizerItemsProc->Add( m_staticTextDataProcessed, 0, wxALIGN_BOTTOM|wxLEFT, 5 );
fgSizer10->Add( bSizerItemsProc, 0, wxALIGN_BOTTOM, 5 );
@@ -2203,38 +2181,26 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
bSizerItemsRem->Add( m_staticTextRemainingObj, 0, wxALIGN_BOTTOM, 5 );
- m_staticText96 = new wxStaticText( m_panelProgress, wxID_ANY, _("("), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText96->Wrap( -1 );
- m_staticText96->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizerItemsRem->Add( m_staticText96, 0, wxLEFT|wxALIGN_BOTTOM, 5 );
-
m_staticTextDataRemaining = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDataRemaining->Wrap( -1 );
m_staticTextDataRemaining->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
- bSizerItemsRem->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM, 5 );
-
- m_staticText97 = new wxStaticText( m_panelProgress, wxID_ANY, _(")"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText97->Wrap( -1 );
- m_staticText97->SetFont( wxFont( 9, 70, 90, 90, false, wxEmptyString ) );
-
- bSizerItemsRem->Add( m_staticText97, 0, wxALIGN_BOTTOM, 5 );
+ bSizerItemsRem->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM|wxLEFT, 5 );
fgSizer10->Add( bSizerItemsRem, 0, wxALIGN_BOTTOM, 5 );
- m_staticTextLabelElapsedTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Elapsed time:"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticTextLabelElapsedTime->Wrap( -1 );
- m_staticTextLabelElapsedTime->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+ m_staticText84 = new wxStaticText( m_panelProgress, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText84->Wrap( -1 );
+ m_staticText84->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- fgSizer10->Add( m_staticTextLabelElapsedTime, 0, wxALIGN_BOTTOM, 5 );
+ fgSizer10->Add( m_staticText84, 0, wxALIGN_BOTTOM, 5 );
- m_staticTextTimeElapsed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticTextTimeElapsed->Wrap( -1 );
- m_staticTextTimeElapsed->SetFont( wxFont( 9, 70, 90, 92, false, wxEmptyString ) );
+ m_staticTextSpeed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextSpeed->Wrap( -1 );
+ m_staticTextSpeed->SetFont( wxFont( 9, 70, 90, 92, false, wxEmptyString ) );
- fgSizer10->Add( m_staticTextTimeElapsed, 0, wxALIGN_BOTTOM, 5 );
+ fgSizer10->Add( m_staticTextSpeed, 0, wxALIGN_BOTTOM, 5 );
m_staticTextLabelRemTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Remaining time:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextLabelRemTime->Wrap( -1 );
@@ -2248,17 +2214,17 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
fgSizer10->Add( m_staticTextRemTime, 0, wxALIGN_BOTTOM, 5 );
- m_staticText84 = new wxStaticText( m_panelProgress, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText84->Wrap( -1 );
- m_staticText84->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+ m_staticTextLabelElapsedTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Elapsed time:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextLabelElapsedTime->Wrap( -1 );
+ m_staticTextLabelElapsedTime->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- fgSizer10->Add( m_staticText84, 0, wxALIGN_BOTTOM, 5 );
+ fgSizer10->Add( m_staticTextLabelElapsedTime, 0, wxALIGN_BOTTOM, 5 );
- m_staticTextSpeed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticTextSpeed->Wrap( -1 );
- m_staticTextSpeed->SetFont( wxFont( 9, 70, 90, 92, false, wxEmptyString ) );
+ m_staticTextTimeElapsed = new wxStaticText( m_panelProgress, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextTimeElapsed->Wrap( -1 );
+ m_staticTextTimeElapsed->SetFont( wxFont( 9, 70, 90, 92, false, wxEmptyString ) );
- fgSizer10->Add( m_staticTextSpeed, 0, wxALIGN_BOTTOM, 5 );
+ fgSizer10->Add( m_staticTextTimeElapsed, 0, wxALIGN_BOTTOM, 5 );
bSizerProgressStat->Add( fgSizer10, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@@ -2320,7 +2286,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
bSizer28->Add( 0, 0, 1, 0, 5 );
- m_buttonOK = new wxButton( m_panelBackground, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( 100,30 ), 0 );
+ m_buttonOK = new wxButton( m_panelBackground, wxID_OK, _("OK"), wxDefaultPosition, wxSize( 100,30 ), 0 );
m_buttonOK->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
m_buttonOK->Enable( false );
@@ -2331,7 +2297,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
bSizer28->Add( m_buttonPause, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- m_buttonAbort = new wxButton( m_panelBackground, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( 100,30 ), 0 );
+ m_buttonAbort = new wxButton( m_panelBackground, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( 100,30 ), 0 );
m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer28->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
@@ -2675,7 +2641,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer31->Add( sbSizer14, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxRIGHT|wxLEFT, 5 );
- m_buttonOkay = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( 100,30 ), 0 );
+ m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( 100,30 ), 0 );
m_buttonOkay->SetDefault();
m_buttonOkay->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -2744,7 +2710,7 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer25->Add( m_buttonRetry, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_buttonAbort = new wxButton( this, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonAbort = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer25->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
@@ -2756,6 +2722,8 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
this->SetSizer( bSizer24 );
this->Layout();
+ 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 );
@@ -2814,7 +2782,7 @@ WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const
bSizer25->Add( m_buttonSwitch, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
- m_buttonAbort = new wxButton( this, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonAbort = new wxButton( this, 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 );
@@ -2826,6 +2794,8 @@ WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const
this->SetSizer( bSizer24 );
this->Layout();
+ 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 );
@@ -2884,7 +2854,7 @@ QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, con
bSizer25->Add( m_buttonNo, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_buttonCancel = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonCancel = new wxButton( this, 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 );
@@ -2896,6 +2866,8 @@ QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, con
this->SetSizer( bSizer24 );
this->Layout();
+ 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 );
@@ -2963,13 +2935,13 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w
wxBoxSizer* bSizer25;
bSizer25 = new wxBoxSizer( wxHORIZONTAL );
- m_buttonOK = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonOK->SetDefault();
m_buttonOK->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer25->Add( m_buttonOK, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
- m_buttonCancel = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonCancel->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer25->Add( m_buttonCancel, 0, wxALL, 5 );
@@ -2984,6 +2956,8 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w
this->SetSizer( bSizer24 );
this->Layout();
+ this->Centre( wxBOTH );
+
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DeleteDlgGenerated::OnClose ) );
m_checkBoxUseRecycler->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DeleteDlgGenerated::OnUseRecycler ), NULL, this );
@@ -3254,13 +3228,13 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer22->Add( 0, 0, 1, wxALIGN_CENTER_VERTICAL, 5 );
- m_button10 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button10 = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button10->SetDefault();
m_button10->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer22->Add( m_button10, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
- m_button17 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button17 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button17->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer22->Add( m_button17, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@@ -3441,13 +3415,13 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind
bSizer97->Add( 0, 0, 1, 0, 5 );
- m_buttonOkay = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonOkay->SetDefault();
m_buttonOkay->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer97->Add( m_buttonOkay, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_button29 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button29 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button29->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer97->Add( m_button29, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -3460,6 +3434,8 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind
this->Layout();
bSizer95->Fit( this );
+ this->Centre( wxBOTH );
+
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GlobalSettingsDlgGenerated::OnClose ) );
m_buttonResetDialogs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GlobalSettingsDlgGenerated::OnResetDialogs ), NULL, this );
@@ -3493,7 +3469,7 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i
wxBoxSizer* bSizer158;
bSizer158 = new wxBoxSizer( wxHORIZONTAL );
- m_buttonStartSync = new zen::BitmapButton( this, wxID_ANY, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 );
+ m_buttonStartSync = new zen::BitmapButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 );
m_buttonStartSync->SetDefault();
m_buttonStartSync->SetFont( wxFont( 14, 70, 90, 92, false, wxEmptyString ) );
m_buttonStartSync->SetToolTip( _("Start synchronization") );
@@ -3659,7 +3635,7 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i
bSizer142->Add( 10, 0, 1, 0, 5 );
- m_button16 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button16 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button16->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer142->Add( m_button16, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
@@ -3672,6 +3648,8 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i
this->Layout();
bSizer134->Fit( this );
+ this->Centre( wxBOTH );
+
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncPreviewDlgGenerated::OnClose ) );
m_buttonStartSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncPreviewDlgGenerated::OnStartSync ), NULL, this );
@@ -3752,7 +3730,7 @@ SearchDialogGenerated::SearchDialogGenerated( wxWindow* parent, wxWindowID id, c
bSizer97->Add( m_buttonFindNext, 0, wxEXPAND|wxTOP|wxRIGHT, 5 );
- m_button29 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button29 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button29->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer97->Add( m_button29, 0, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 5 );
@@ -3763,7 +3741,8 @@ SearchDialogGenerated::SearchDialogGenerated( wxWindow* parent, wxWindowID id, c
this->SetSizer( bSizer161 );
this->Layout();
- bSizer161->Fit( this );
+
+ this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SearchDialogGenerated::OnClose ) );
@@ -3807,13 +3786,13 @@ SelectTimespanDlgGenerated::SelectTimespanDlgGenerated( wxWindow* parent, wxWind
bSizer97->Add( 0, 0, 1, wxEXPAND, 5 );
- m_buttonOkay = new wxButton( this, wxID_ANY, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonOkay = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonOkay->SetDefault();
m_buttonOkay->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
bSizer97->Add( m_buttonOkay, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_button29 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_button29 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button29->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
bSizer97->Add( m_button29, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@@ -3829,6 +3808,8 @@ SelectTimespanDlgGenerated::SelectTimespanDlgGenerated( wxWindow* parent, wxWind
this->Layout();
bSizer96->Fit( this );
+ this->Centre( wxBOTH );
+
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SelectTimespanDlgGenerated::OnClose ) );
m_calendarFrom->Connect( wxEVT_CALENDAR_SEL_CHANGED, wxCalendarEventHandler( SelectTimespanDlgGenerated::OnChangeSelectionFrom ), NULL, this );
diff --git a/ui/gui_generated.h b/ui/gui_generated.h
index 8176dbf9..bd7c6be4 100644
--- a/ui/gui_generated.h
+++ b/ui/gui_generated.h
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Mar 17 2012)
+// C++ code generated with wxFormBuilder (version Apr 10 2012)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@@ -262,9 +262,7 @@ protected:
wxBoxSizer* bSizerFilesRemaining;
wxStaticText* m_staticText46;
wxStaticText* m_staticTextFilesRemaining;
- wxStaticText* m_staticText117;
wxStaticText* m_staticTextDataRemaining;
- wxStaticText* m_staticText118;
wxBoxSizer* sSizerSpeed;
wxStaticText* m_staticText104;
wxStaticText* m_staticTextSpeed;
@@ -527,21 +525,17 @@ protected:
wxStaticText* m_staticTextLabelItemsProc;
wxBoxSizer* bSizerItemsProc;
wxStaticText* m_staticTextProcessedObj;
- wxStaticText* m_staticText98;
wxStaticText* m_staticTextDataProcessed;
- wxStaticText* m_staticText99;
wxStaticText* m_staticTextLabelItemsRem;
wxBoxSizer* bSizerItemsRem;
wxStaticText* m_staticTextRemainingObj;
- wxStaticText* m_staticText96;
wxStaticText* m_staticTextDataRemaining;
- wxStaticText* m_staticText97;
- wxStaticText* m_staticTextLabelElapsedTime;
- wxStaticText* m_staticTextTimeElapsed;
- wxStaticText* m_staticTextLabelRemTime;
- wxStaticText* m_staticTextRemTime;
wxStaticText* m_staticText84;
wxStaticText* m_staticTextSpeed;
+ wxStaticText* m_staticTextLabelRemTime;
+ wxStaticText* m_staticTextRemTime;
+ wxStaticText* m_staticTextLabelElapsedTime;
+ wxStaticText* m_staticTextTimeElapsed;
zen::Graph2D* m_panelGraph;
wxBoxSizer* bSizerFinalStat;
wxListbook* m_listbookResult;
@@ -948,7 +942,7 @@ protected:
public:
- SearchDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Find"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
+ SearchDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Find"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 384,97 ), long style = wxDEFAULT_DIALOG_STYLE );
~SearchDialogGenerated();
};
diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp
index 6e3c08a0..65e40410 100644
--- a/ui/gui_status_handler.cpp
+++ b/ui/gui_status_handler.cpp
@@ -5,13 +5,11 @@
// **************************************************************************
#include "gui_status_handler.h"
-#include "small_dlgs.h"
+#include <wx/wupdlock.h>
+#include <wx+/shell_execute.h>
#include "msg_popup.h"
#include "main_dlg.h"
-#include <wx/wupdlock.h>
-#include <wx+/string_conv.h>
#include "exec_finished_box.h"
-#include <wx+/shell_execute.h>
using namespace zen;
using namespace xmlAccess;
@@ -19,24 +17,24 @@ using namespace xmlAccess;
CompareStatusHandler::CompareStatusHandler(MainDialog& dlg) :
mainDlg(dlg),
- ignoreErrors(false),
- currentProcess(StatusHandler::PROCESS_NONE)
+ ignoreErrors(false)
{
- wxWindowUpdateLocker dummy(&mainDlg); //avoid display distortion
+ {
+ wxWindowUpdateLocker dummy(&mainDlg); //avoid display distortion
- //prevent user input during "compare", do not disable maindialog since abort-button would also be disabled
- mainDlg.disableAllElements(true);
- mainDlg.compareStatus->init(); //clear old values
+ //prevent user input during "compare", do not disable maindialog since abort-button would also be disabled
+ mainDlg.disableAllElements(true);
- //display status panel during compare
- mainDlg.auiMgr.GetPane(mainDlg.compareStatus->getAsWindow()).Show();
- mainDlg.auiMgr.Update();
- mainDlg.compareStatus->updateStatusPanelNow(); //clear gui flicker: window must be visible to make this work!
+ //display status panel during compare
+ mainDlg.compareStatus->init(*this); //clear old values before showing panel
+ mainDlg.auiMgr.GetPane(mainDlg.compareStatus->getAsWindow()).Show();
+ mainDlg.auiMgr.Update();
- //register abort button
- mainDlg.m_buttonAbort->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CompareStatusHandler::OnAbortCompare), nullptr, this);
- //register key event
- mainDlg.Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(CompareStatusHandler::OnKeyPressed), nullptr, this);
+ //register keys
+ mainDlg.Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(CompareStatusHandler::OnKeyPressed), nullptr, this);
+ mainDlg.m_buttonAbort->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CompareStatusHandler::OnAbortCompare), nullptr, this);
+ }
+ mainDlg.Update(); //don't wait until idle event!
}
@@ -46,17 +44,17 @@ CompareStatusHandler::~CompareStatusHandler()
//reenable complete main dialog
mainDlg.enableAllElements();
- mainDlg.compareStatus->finalize();
+ mainDlg.compareStatus->finalize();
mainDlg.auiMgr.GetPane(mainDlg.compareStatus->getAsWindow()).Hide();
mainDlg.auiMgr.Update();
- if (abortIsRequested())
- mainDlg.pushStatusInformation(_("Operation aborted!"));
-
- //de-register keys
+ //unregister keys
mainDlg.Disconnect(wxEVT_CHAR_HOOK, wxKeyEventHandler(CompareStatusHandler::OnKeyPressed), nullptr, this);
mainDlg.m_buttonAbort->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CompareStatusHandler::OnAbortCompare), nullptr, this);
+
+ if (abortIsRequested())
+ mainDlg.pushStatusInformation(_("Operation aborted!"));
}
@@ -73,71 +71,29 @@ void CompareStatusHandler::OnKeyPressed(wxKeyEvent& event)
}
-void CompareStatusHandler::initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID)
+void CompareStatusHandler::initNewPhase(int objectsTotal, Int64 dataTotal, Phase phaseID)
{
- currentProcess = processID;
+ StatusHandler::initNewPhase(objectsTotal, dataTotal, phaseID);
- switch (currentProcess)
+ switch (currentPhase())
{
- case StatusHandler::PROCESS_SCANNING:
+ case PHASE_NONE:
+ case PHASE_SYNCHRONIZING:
+ assert(false);
+ case PHASE_SCANNING:
break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
+ case PHASE_COMPARING_CONTENT:
{
wxWindowUpdateLocker dummy(&mainDlg);
- mainDlg.compareStatus->switchToCompareBytewise(objectsTotal, dataTotal);
+ mainDlg.compareStatus->switchToCompareBytewise();
mainDlg.Layout(); //show progress bar...
mainDlg.Refresh(); //remove distortion...
}
break;
- case StatusHandler::PROCESS_SYNCHRONIZING:
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
}
}
-void CompareStatusHandler::updateProcessedData(int objectsDelta, zen::Int64 dataDelta)
-{
- switch (currentProcess)
- {
- case StatusHandler::PROCESS_SCANNING:
- mainDlg.compareStatus->incScannedObjects_NoUpdate(objectsDelta); //throw ()
- break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- mainDlg.compareStatus->incProcessedCmpData_NoUpdate(objectsDelta, dataDelta); //throw ()
- break;
- case StatusHandler::PROCESS_SYNCHRONIZING:
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
- }
-
- //note: this method must NOT throw in order to properly allow undoing setting of statistics!
-}
-
-
-void CompareStatusHandler::updateTotalData(int objectsDelta, Int64 dataDelta)
-{
- assert(currentProcess != PROCESS_SCANNING);
- mainDlg.compareStatus->incTotalCmpData_NoUpdate(objectsDelta, dataDelta);
-}
-
-
-void CompareStatusHandler::reportStatus(const std::wstring& text)
-{
- mainDlg.compareStatus->setStatusText_NoUpdate(text);
- requestUiRefresh(); //throw AbortThisProcess
-}
-
-
-void CompareStatusHandler::reportInfo(const std::wstring& text)
-{
- mainDlg.compareStatus->setStatusText_NoUpdate(text);
- requestUiRefresh(); //throw AbortThisProcess
-}
-
-
ProcessCallback::Response CompareStatusHandler::reportError(const std::wstring& message)
{
if (ignoreErrors)
@@ -146,7 +102,8 @@ ProcessCallback::Response CompareStatusHandler::reportError(const std::wstring&
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ switch (showErrorDlg(&mainDlg,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
message, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
@@ -169,8 +126,7 @@ void CompareStatusHandler::reportFatalError(const std::wstring& errorMessage)
{
forceUiRefresh();
- showErrorDlg(ReturnErrorDlg::BUTTON_ABORT,
- errorMessage, nullptr);
+ showErrorDlg(&mainDlg, ReturnErrorDlg::BUTTON_ABORT, errorMessage, nullptr);
}
@@ -183,9 +139,9 @@ void CompareStatusHandler::reportWarning(const std::wstring& warningMessage, boo
//show pop-up and ask user how to handle warning
bool dontWarnAgain = false;
- switch (showWarningDlg(ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
- warningMessage,
- dontWarnAgain))
+ switch (showWarningDlg(&mainDlg,
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
+ warningMessage, dontWarnAgain))
{
case ReturnWarningDlg::BUTTON_IGNORE:
warningActive = !dontWarnAgain;
@@ -214,7 +170,7 @@ void CompareStatusHandler::OnAbortCompare(wxCommandEvent& event)
void CompareStatusHandler::abortThisProcess()
{
- requestAbortion();
+ requestAbortion(); //just make sure...
throw GuiAbortProcess();
}
//########################################################################################################
@@ -226,7 +182,7 @@ SyncStatusHandler::SyncStatusHandler(MainDialog* parentDlg,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory) :
parentDlg_(parentDlg),
- syncStatusFrame(*this, parentDlg, SyncStatus::SYNCHRONIZING, true, jobName, execWhenFinished, execFinishedHistory),
+ syncStatusFrame(*this, *this, parentDlg, true, jobName, execWhenFinished, execFinishedHistory),
handleError_(handleError)
{
}
@@ -238,11 +194,17 @@ SyncStatusHandler::~SyncStatusHandler()
//finalize error log
if (abortIsRequested())
- errorLog.logMsg(_("Synchronization aborted!"), TYPE_FATAL_ERROR);
+ errorLog.logMsg(_("Synchronization aborted!"), TYPE_ERROR);
else if (totalErrors > 0)
errorLog.logMsg(_("Synchronization completed with errors!"), TYPE_WARNING);
else
- errorLog.logMsg(_("Synchronization completed successfully!"), TYPE_INFO);
+ {
+ 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!
+ else
+ errorLog.logMsg(_("Synchronization completed successfully!"), TYPE_INFO);
+ }
bool showFinalResults = true;
@@ -260,60 +222,37 @@ SyncStatusHandler::~SyncStatusHandler()
if (showFinalResults)
{
if (abortIsRequested())
- syncStatusFrame.processHasFinished(SyncStatus::ABORTED, errorLog); //enable okay and close events
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_ABORTED, errorLog); //enable okay and close events
else if (totalErrors > 0)
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_ERROR, errorLog);
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_FINISHED_WITH_ERROR, errorLog);
else
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS, errorLog);
+ syncStatusFrame.processHasFinished(SyncStatus::RESULT_FINISHED_WITH_SUCCESS, errorLog);
}
else
syncStatusFrame.closeWindowDirectly(); //syncStatusFrame is main window => program will quit directly
}
-void SyncStatusHandler::initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID)
+void SyncStatusHandler::initNewPhase(int objectsTotal, Int64 dataTotal, Phase phaseID)
{
- switch (processID)
- {
- case StatusHandler::PROCESS_SYNCHRONIZING:
- syncStatusFrame.initNewProcess(SyncStatus::SYNCHRONIZING, objectsTotal, dataTotal);
- break;
- case StatusHandler::PROCESS_SCANNING:
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
- }
+ assert(phaseID == PHASE_SYNCHRONIZING);
+ StatusHandler::initNewPhase(objectsTotal, dataTotal, phaseID);
+ syncStatusFrame.initNewPhase(); //call after "StatusHandler::initNewPhase"
}
void SyncStatusHandler::updateProcessedData(int objectsDelta, Int64 dataDelta)
{
- syncStatusFrame.incProcessedData_NoUpdate(objectsDelta, dataDelta); //throw ()
-
+ StatusHandler::updateProcessedData(objectsDelta, dataDelta);
+ syncStatusFrame.reportCurrentBytes(getDataCurrent(currentPhase())); //throw ()
//note: this method should NOT throw in order to properly allow undoing setting of statistics!
}
-void SyncStatusHandler::updateTotalData(int objectsDelta, Int64 dataDelta)
-{
- syncStatusFrame.incTotalData_NoUpdate(objectsDelta, dataDelta); //throw ()
-}
-
-
-void SyncStatusHandler::reportStatus(const std::wstring& text)
-{
- syncStatusFrame.setStatusText_NoUpdate(text); //throw ()
- requestUiRefresh(); //throw AbortThisProccess
-}
-
-
void SyncStatusHandler::reportInfo(const std::wstring& text)
{
+ StatusHandler::reportInfo(text);
errorLog.logMsg(text, TYPE_INFO);
-
- syncStatusFrame.setStatusText_NoUpdate(text); //throw ()
- requestUiRefresh(); //throw AbortThisProccess
}
@@ -332,7 +271,8 @@ ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& err
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ switch (showErrorDlg(parentDlg_,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
errorMessage,
&ignoreNextErrors))
{
@@ -351,9 +291,8 @@ ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& err
break;
}
- assert (false);
- errorLog.logMsg(errorMessage, TYPE_ERROR);
- return ProcessCallback::IGNORE_ERROR;
+ assert(false);
+ return ProcessCallback::IGNORE_ERROR; //dummy value
}
@@ -369,9 +308,9 @@ void SyncStatusHandler::reportFatalError(const std::wstring& errorMessage)
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
- errorMessage,
- &ignoreNextErrors))
+ switch (showErrorDlg(parentDlg_,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
+ errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
if (ignoreNextErrors) //falsify only
@@ -398,47 +337,48 @@ void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
{
errorLog.logMsg(warningMessage, TYPE_WARNING);
+ if (!warningActive)
+ return;
+
switch (handleError_)
{
case ON_GUIERROR_POPUP:
- break;
- case ON_GUIERROR_IGNORE:
- return; //if errors are ignored, then warnings should also
- }
- if (!warningActive)
- return;
+ {
+ PauseTimers dummy(syncStatusFrame);
+ forceUiRefresh();
- PauseTimers dummy(syncStatusFrame);
- forceUiRefresh();
+ bool dontWarnAgain = false;
+ switch (showWarningDlg(parentDlg_,
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
+ warningMessage, dontWarnAgain))
+ {
+ case ReturnWarningDlg::BUTTON_IGNORE: //no unhandled error situation!
+ warningActive = !dontWarnAgain;
+ break;
- bool dontWarnAgain = false;
- switch (showWarningDlg(ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
- warningMessage,
- dontWarnAgain))
- {
- case ReturnWarningDlg::BUTTON_IGNORE: //no unhandled error situation!
- warningActive = !dontWarnAgain;
- return;
+ case ReturnWarningDlg::BUTTON_SWITCH:
+ assert(false);
+ case ReturnWarningDlg::BUTTON_ABORT:
+ abortThisProcess();
+ break;
+ }
+ }
+ break;
- case ReturnWarningDlg::BUTTON_SWITCH:
- assert(false);
- case ReturnWarningDlg::BUTTON_ABORT:
- abortThisProcess();
- return;
+ case ON_GUIERROR_IGNORE:
+ break; //if errors are ignored, then warnings should be, too
}
-
- assert(false);
}
void SyncStatusHandler::forceUiRefresh()
{
- syncStatusFrame.updateStatusDialogNow();
+ syncStatusFrame.updateProgress();
}
void SyncStatusHandler::abortThisProcess()
{
- requestAbortion();
+ requestAbortion(); //just make sure...
throw GuiAbortProcess(); //abort can be triggered by syncStatusFrame
}
diff --git a/ui/gui_status_handler.h b/ui/gui_status_handler.h
index 4e289648..ebc59473 100644
--- a/ui/gui_status_handler.h
+++ b/ui/gui_status_handler.h
@@ -21,17 +21,13 @@ class wxCommandEvent;
class GuiAbortProcess {};
//classes handling sync and compare error as well as status information
-class CompareStatusHandler : private wxEvtHandler, public StatusHandler
+class CompareStatusHandler : private wxEvtHandler, public zen::StatusHandler
{
public:
CompareStatusHandler(MainDialog& dlg);
~CompareStatusHandler();
- virtual void initNewProcess (int objectsTotal, zen::Int64 dataTotal, Process processID);
- virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta);
- virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta);
- virtual void reportStatus(const std::wstring& text);
- virtual void reportInfo(const std::wstring& text);
+ virtual void initNewPhase (int objectsTotal, zen::Int64 dataTotal, Phase phaseID);
virtual void forceUiRefresh();
virtual Response reportError(const std::wstring& text);
@@ -41,15 +37,14 @@ public:
private:
void OnKeyPressed(wxKeyEvent& event);
void OnAbortCompare(wxCommandEvent& event); //handle abort button click
- virtual void abortThisProcess();
+ virtual void abortThisProcess(); //throw GuiAbortProcess
MainDialog& mainDlg;
bool ignoreErrors;
- Process currentProcess;
};
-class SyncStatusHandler : public StatusHandler
+class SyncStatusHandler : public zen::StatusHandler
{
public:
SyncStatusHandler(MainDialog* parentDlg,
@@ -59,10 +54,8 @@ public:
std::vector<std::wstring>& execFinishedHistory);
~SyncStatusHandler();
- virtual void initNewProcess (int objectsTotal, zen::Int64 dataTotal, Process processID);
+ virtual void initNewPhase (int objectsTotal, zen::Int64 dataTotal, Phase phaseID);
virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta);
- virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta);
- virtual void reportStatus(const std::wstring& text);
virtual void reportInfo(const std::wstring& text);
virtual void forceUiRefresh();
@@ -71,7 +64,7 @@ public:
virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive);
private:
- virtual void abortThisProcess();
+ virtual void abortThisProcess(); //throw GuiAbortProcess
MainDialog* parentDlg_;
SyncStatus syncStatusFrame; //the window managed by SyncStatus has longer lifetime than this handler!
diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp
index 85f9a580..049a1176 100644
--- a/ui/main_dlg.cpp
+++ b/ui/main_dlg.cpp
@@ -39,8 +39,8 @@
#include "../lib/resources.h"
#include <zen/file_handling.h>
#include <zen/file_id.h>
+#include <zen/recycler.h>
#include "../lib/resolve_path.h"
-#include "../lib/recycler.h"
#include "../lib/ffs_paths.h"
#include <wx+/toggle_button.h>
#include "folder_pair.h"
@@ -119,7 +119,7 @@ public:
return false;
}
- switch (xmlAccess::getMergeType(droppedFiles)) //throw ()
+ switch (xmlAccess::getMergeType(toZ(droppedFiles))) //throw()
{
case xmlAccess::MERGE_BATCH:
case xmlAccess::MERGE_GUI:
@@ -363,20 +363,20 @@ MainDialog::MainDialog(const std::vector<wxString>& cfgFileNames, xmlAccess::Xml
//------------------------------------------------------------------------------------------
//check existence of all directories in parallel!
- std::list<boost::unique_future<bool>> fileEx;
+
+ RunUntilFirstHit<NullType> findFirstMissing;
std::for_each(filenames.begin(), filenames.end(),
- [&fileEx](const wxString& filename)
+ [&](const wxString& filename)
{
const Zstring filenameFmt = toZ(filename); //convert to Zstring first: we don't want to pass wxString by value and risk MT issues!
- fileEx.push_back(zen::async2<bool>([=]() { return !filenameFmt.empty() && zen::fileExists(filenameFmt); }));
+ findFirstMissing.addJob([=] { return filenameFmt.empty() || !fileExists(filenameFmt) ? zen::make_unique<NullType>() : nullptr; });
});
//potentially slow network access: give all checks 500ms to finish
- wait_for_all_timed(fileEx.begin(), fileEx.end(), boost::posix_time::milliseconds(500));
+ const bool allFilesExist = findFirstMissing.timedWait(boost::posix_time::milliseconds(500)) && //false: time elapsed
+ !findFirstMissing.get(); //no missing
//------------------------------------------------------------------------------------------
- //check if one of the files is not existing (this shall not be an error!)
- const bool allFilesExist = std::all_of(fileEx.begin(), fileEx.end(), [](boost::unique_future<bool>& ft) { return ft.is_ready() && ft.get(); });
if (!allFilesExist)
filenames.clear();
@@ -392,16 +392,16 @@ MainDialog::MainDialog(const std::vector<wxString>& cfgFileNames, xmlAccess::Xml
try
{
//load XML
- xmlAccess::convertConfig(filenames, guiCfg); //throw (xmlAccess::FfsXmlError)
+ xmlAccess::convertConfig(toZ(filenames), guiCfg); //throw xmlAccess::FfsXmlError
loadCfgSuccess = true;
}
catch (const xmlAccess::FfsXmlError& error)
{
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING);
+ wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
else
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
}
const bool startComparisonImmediately = !cfgFileNames.empty() && loadCfgSuccess;
@@ -437,7 +437,7 @@ MainDialog::~MainDialog()
const xmlAccess::XmlGuiConfig guiCfg = getConfig();
try
{
- xmlAccess::writeConfig(guiCfg, lastRunConfigName());
+ xmlAccess::writeConfig(guiCfg, toZ(lastRunConfigName()));
//setLastUsedConfig(lastRunConfigName(), guiCfg); -> may be removed!?
}
//don't annoy users on read-only drives: no error checking should be fine since this is not a config the user explicitly wanted to save
@@ -456,7 +456,7 @@ MainDialog::~MainDialog()
void MainDialog::onQueryEndSession()
{
writeGlobalSettings();
- try { xmlAccess::writeConfig(getConfig(), lastRunConfigName()); }
+ try { xmlAccess::writeConfig(getConfig(), toZ(lastRunConfigName())); }
catch (const xmlAccess::FfsXmlError&) {}
}
@@ -703,29 +703,31 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig& guiCfg,
//------------------------------------------------------------------------------------------
//check existence of all directories in parallel!
- std::list<boost::unique_future<bool>> dirEx;
+ RunUntilFirstHit<NullType> findFirstMissing;
- auto addDirCheck = [&dirEx](const FolderPairEnh& fp)
+ bool haveNonEmptyPair = false;
+ auto addDirCheck = [&](const FolderPairEnh& fp)
{
- const Zstring dirFmtLeft = zen::getFormattedDirectoryName(fp.leftDirectory);
- const Zstring dirFmtRight = zen::getFormattedDirectoryName(fp.rightDirectory);
+ const Zstring dirFmtLeft = getFormattedDirectoryName(fp.leftDirectory ); //should not block!?
+ const Zstring dirFmtRight = getFormattedDirectoryName(fp.rightDirectory); //
if (dirFmtLeft.empty() && dirFmtRight.empty()) //only skip check if both sides are empty!
return;
-
- dirEx.push_back(zen::async2<bool>([=] { return !dirFmtLeft .empty() && zen::dirExists(dirFmtLeft); }));
- dirEx.push_back(zen::async2<bool>([=] { return !dirFmtRight.empty() && zen::dirExists(dirFmtRight); }));
+ haveNonEmptyPair = true;
+ findFirstMissing.addJob([=] { return dirFmtLeft .empty() || !dirExists(dirFmtLeft ) ? zen::make_unique<NullType>() : nullptr; });
+ findFirstMissing.addJob([=] { return dirFmtRight.empty() || !dirExists(dirFmtRight) ? zen::make_unique<NullType>() : nullptr; });
};
+
addDirCheck(currMainCfg.firstPair);
std::for_each(currMainCfg.additionalPairs.begin(), currMainCfg.additionalPairs.end(), addDirCheck);
- if (!dirEx.empty())
+ //------------------------------------------------------------------------------------------
+
+ if (haveNonEmptyPair)
{
//potentially slow network access: give all checks 500ms to finish
- wait_for_all_timed(dirEx.begin(), dirEx.end(), boost::posix_time::milliseconds(500));
- //------------------------------------------------------------------------------------------
-
- const bool allFoldersExist = std::all_of(dirEx.begin(), dirEx.end(), [](boost::unique_future<bool>& ft) { return ft.is_ready() && ft.get(); });
- if (allFoldersExist)
+ const bool allFilesExist = findFirstMissing.timedWait(boost::posix_time::milliseconds(500)) && //true: have result
+ !findFirstMissing.get(); //no missing
+ if (allFilesExist)
{
wxCommandEvent dummy2(wxEVT_COMMAND_BUTTON_CLICKED);
m_buttonCompare->GetEventHandler()->AddPendingEvent(dummy2); //simulate button click on "compare"
@@ -816,9 +818,9 @@ void MainDialog::writeGlobalSettings()
//write list of last used configuration files
std::vector<wxString> cfgFileHistory;
- for (int i = 0; i < static_cast<int>(m_listBoxHistory->GetCount()); ++i)
- if (m_listBoxHistory->GetClientObject(i))
- cfgFileHistory.push_back(static_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(i))->name_);
+ for (unsigned int i = 0; i < m_listBoxHistory->GetCount(); ++i)
+ if (auto clientString = dynamic_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(i)))
+ cfgFileHistory.push_back(clientString->name_);
globalSettings->gui.cfgFileHistory = cfgFileHistory;
globalSettings->gui.lastUsedConfigFiles = activeConfigFiles;
@@ -951,9 +953,7 @@ std::vector<FileSystemObject*> MainDialog::getGridSelection(bool fromLeft, bool
if (fromRight)
addSelection(gridview::COMP_RIGHT);
- std::vector<FileSystemObject*> selection;
- gridDataView->getAllFileRef(selectedRows, selection);
- return selection;
+ return gridDataView->getAllFileRef(selectedRows);
}
@@ -1022,7 +1022,8 @@ public:
return DeleteFilesHandler::IGNORE_ERROR;
bool ignoreNextErrors = false;
- switch (showErrorDlg(ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ switch (showErrorDlg(mainDlg,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
@@ -1094,7 +1095,8 @@ void MainDialog::deleteSelectedFiles(const std::vector<FileSystemObject*>& selec
wxWindow* oldFocus = wxWindow::FindFocus();
ZEN_ON_SCOPE_EXIT( if (oldFocus) oldFocus->SetFocus(); )
- if (zen::showDeleteDialog(selectionLeft,
+ if (zen::showDeleteDialog(this,
+ selectionLeft,
selectionRight,
globalSettings->gui.deleteOnBothSides,
globalSettings->gui.useRecyclerForManualDeletion) == ReturnSmallDlg::BUTTON_OKAY)
@@ -1535,7 +1537,7 @@ void MainDialog::OnGlobalKeyEvent(wxKeyEvent& event) //process key events withou
switch (keyCode)
{
case 'F': //CTRL + F
- zen::startFind(*this, *m_gridMain, gridview::COMP_LEFT, gridview::COMP_RIGHT, globalSettings->gui.textSearchRespectCase);
+ zen::startFind(this, *m_gridMain, gridview::COMP_LEFT, gridview::COMP_RIGHT, globalSettings->gui.textSearchRespectCase);
return; //-> swallow event!
}
@@ -1543,7 +1545,7 @@ void MainDialog::OnGlobalKeyEvent(wxKeyEvent& event) //process key events withou
{
case WXK_F3: //F3
case WXK_NUMPAD_F3: //
- zen::findNext(*this, *m_gridMain, gridview::COMP_LEFT, gridview::COMP_RIGHT, globalSettings->gui.textSearchRespectCase);
+ zen::findNext(this, *m_gridMain, gridview::COMP_LEFT, gridview::COMP_RIGHT, globalSettings->gui.textSearchRespectCase);
return; //-> swallow event!
case WXK_F8: //F8
@@ -1679,15 +1681,19 @@ void MainDialog::onNaviGridContext(GridClickEvent& event)
menu.addItem(_("Exclude temporarily") + L"\tSpace", [] {}, nullptr, false);
//----------------------------------------------------------------------------------------------------
- //CONTEXT_EXCLUDE_OBJ
+ //EXCLUDE FILTER
if (selection.size() == 1)
- menu.addItem(_("Exclude via filter:") + L" " + afterLast(selection[0]->getObjRelativeName(), FILE_NAME_SEPARATOR),
- [this, &selection] { excludeItems(selection); },
- &GlobalResources::getImage(L"filterOnSmall"));
+ {
+ //by relative path
+ menu.addItem(_("Exclude via filter:") + L" " + (FILE_NAME_SEPARATOR + selection[0]->getObjRelativeName()),
+ [this, &selection] { excludeItems(selection); }, &GlobalResources::getImage(L"filterOnSmall"));
+ }
else if (selection.size() > 1)
+ {
+ //by relative path
menu.addItem(_("Exclude via filter:") + L" " + _("<multiple selection>"),
- [this, &selection] { excludeItems(selection); },
- &GlobalResources::getImage(L"filterOnSmall"));
+ [this, &selection] { excludeItems(selection); }, &GlobalResources::getImage(L"filterOnSmall"));
+ }
//----------------------------------------------------------------------------------------------------
//CONTEXT_DELETE_FILES
@@ -1743,30 +1749,40 @@ void MainDialog::onMainGridContext(GridClickEvent& event)
menu.addItem(_("Exclude temporarily") + L"\tSpace", [] {}, nullptr, false);
//----------------------------------------------------------------------------------------------------
- //CONTEXT_EXCLUDE_EXT
- if (!selection.empty() &&
- dynamic_cast<const DirMapping*>(selection[0]) == nullptr) //non empty && no directory
+ //EXCLUDE FILTER
+ if (selection.size() == 1)
{
- const Zstring filename = afterLast(selection[0]->getObjRelativeName(), FILE_NAME_SEPARATOR);
- if (filename.find(Zchar('.')) != Zstring::npos) //be careful: AfterLast would return the whole string if '.' were not found!
+ ContextMenu submenu;
+
+ //by extension
+ if (dynamic_cast<const DirMapping*>(selection[0]) == nullptr) //non empty && no directory
{
- const Zstring extension = afterLast(filename, Zchar('.'));
+ const Zstring filename = afterLast(selection[0]->getObjRelativeName(), FILE_NAME_SEPARATOR);
+ if (contains(filename, Zchar('.'))) //be careful: AfterLast would return the whole string if '.' were not found!
+ {
+ const Zstring extension = afterLast(filename, Zchar('.'));
- menu.addItem(_("Exclude via filter:") + L" *." + extension,
- [this, extension] { excludeExtension(extension); },
- &GlobalResources::getImage(L"filterOnSmall"));
+ submenu.addItem(L"*." + utf8CvrtTo<wxString>(extension),
+ [this, extension] { excludeExtension(extension); });
+ }
}
+
+ //by short name
+ submenu.addItem(utf8CvrtTo<wxString>(Zstring(Zstr("*")) + FILE_NAME_SEPARATOR + selection[0]->getObjShortName()),
+ [this, &selection] { excludeShortname(*selection[0]); });
+
+ //by relative path
+ submenu.addItem(utf8CvrtTo<wxString>(FILE_NAME_SEPARATOR + selection[0]->getObjRelativeName()),
+ [this, &selection] { excludeItems(selection); });
+
+ menu.addSubmenu(_("Exclude via filter:"), submenu, &GlobalResources::getImage(L"filterOnSmall"));
}
- //----------------------------------------------------------------------------------------------------
- //CONTEXT_EXCLUDE_OBJ
- if (selection.size() == 1)
- menu.addItem(_("Exclude via filter:") + L" " + afterLast(selection[0]->getObjRelativeName(), FILE_NAME_SEPARATOR),
- [this, &selection] { excludeItems(selection); },
- &GlobalResources::getImage(L"filterOnSmall"));
else if (selection.size() > 1)
+ {
+ //by relative path
menu.addItem(_("Exclude via filter:") + L" " + _("<multiple selection>"),
- [this, &selection] { excludeItems(selection); },
- &GlobalResources::getImage(L"filterOnSmall"));
+ [this, &selection] { excludeItems(selection); }, &GlobalResources::getImage(L"filterOnSmall"));
+ }
//----------------------------------------------------------------------------------------------------
//CONTEXT_EXTERNAL_APP
@@ -1836,10 +1852,28 @@ void MainDialog::excludeExtension(const Zstring& extension)
updateFilterButtons();
//do not fully apply filter, just exclude new items
- std::for_each(begin(folderCmp), end(folderCmp),
- [&](BaseDirMapping& baseMap) { addHardFiltering(baseMap, newExclude); });
+ std::for_each(begin(folderCmp), end(folderCmp), [&](BaseDirMapping& baseMap) { addHardFiltering(baseMap, newExclude); });
+ updateGui();
+}
- //applyFiltering(getConfig().mainCfg, gridDataView->getDataTentative());
+
+void MainDialog::excludeShortname(const FileSystemObject& fsObj)
+{
+ Zstring newExclude = Zstring(Zstr("*")) + FILE_NAME_SEPARATOR + fsObj.getObjShortName();
+ const bool isDir = dynamic_cast<const DirMapping*>(&fsObj) != nullptr;
+ if (isDir)
+ newExclude += FILE_NAME_SEPARATOR;
+
+ //add to filter config
+ Zstring& excludeFilter = currentCfg.mainCfg.globalFilter.excludeFilter;
+ if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
+ excludeFilter += Zstr("\n");
+ excludeFilter += newExclude;
+
+ updateFilterButtons();
+
+ //do not fully apply filter, just exclude new items
+ std::for_each(begin(folderCmp), end(folderCmp), [&](BaseDirMapping& baseMap) { addHardFiltering(baseMap, newExclude); });
updateGui();
}
@@ -1856,7 +1890,7 @@ void MainDialog::excludeItems(const std::vector<FileSystemObject*>& selection)
if (iter != selection.begin())
newExclude += Zstr("\n");
- //#pragma warning(suppress: 6011) -> fsObj cannot be NULL here!
+ //#pragma warning(suppress: 6011) -> fsObj bound in this context!
newExclude += FILE_NAME_SEPARATOR + fsObj->getObjRelativeName();
const bool isDir = dynamic_cast<const DirMapping*>(fsObj) != nullptr;
@@ -1873,10 +1907,7 @@ void MainDialog::excludeItems(const std::vector<FileSystemObject*>& selection)
updateFilterButtons();
//do not fully apply filter, just exclude new items
- std::for_each(begin(folderCmp), end(folderCmp),
- [&](BaseDirMapping& baseMap) { addHardFiltering(baseMap, newExclude); });
-
- //applyFiltering(getConfig().mainCfg, gridDataView->getDataTentative());
+ std::for_each(begin(folderCmp), end(folderCmp), [&](BaseDirMapping& baseMap) { addHardFiltering(baseMap, newExclude); });
updateGui();
}
}
@@ -1953,7 +1984,7 @@ void MainDialog::onGridLabelContext(GridClickEvent& event)
auto selectTimeSpan = [&]
{
- if (showSelectTimespanDlg(manualTimeSpanFrom, manualTimeSpanTo) == ReturnSmallDlg::BUTTON_OKAY)
+ if (showSelectTimespanDlg(this, manualTimeSpanFrom, manualTimeSpanTo) == ReturnSmallDlg::BUTTON_OKAY)
{
applyTimeSpanFilter(folderCmp, manualTimeSpanFrom, manualTimeSpanTo); //overwrite current active/inactive settings
updateGuiAfterFilterChange(400);
@@ -2062,22 +2093,8 @@ void MainDialog::OnDirSelected(wxFileDirPickerEvent& event)
void MainDialog::onNaviPanelFilesDropped(FileDropEvent& event)
{
- const auto& droppedFiles = event.getFiles();
-
- switch (xmlAccess::getMergeType(droppedFiles)) //throw ()
- {
- case xmlAccess::MERGE_BATCH:
- case xmlAccess::MERGE_GUI:
- case xmlAccess::MERGE_GUI_BATCH:
- loadConfiguration(droppedFiles);
- return;
-
- case xmlAccess::MERGE_OTHER:
- break;
- }
-
+ loadConfiguration(event.getFiles());
event.Skip();
-
}
@@ -2180,17 +2197,17 @@ bool MainDialog::trySaveConfig(const wxString* fileName) //return true if saved
targetFilename = *fileName;
else
{
- wxString defaultFileName = activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? activeConfigFiles[0] : wxT("SyncSettings.ffs_gui");
+ wxString defaultFileName = activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? activeConfigFiles[0] : L"SyncSettings.ffs_gui";
//attention: activeConfigFiles may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
- if (defaultFileName.EndsWith(wxT(".ffs_batch")))
- defaultFileName.Replace(wxT(".ffs_batch"), wxT(".ffs_gui"), false);
+ if (endsWith(defaultFileName, L".ffs_batch"))
+ replace(defaultFileName, L".ffs_batch", L".ffs_gui", false);
- wxFileDialog filePicker(this,
+ wxFileDialog filePicker(this, //put modal dialog on stack: creating this on freestore leads to memleak!
wxEmptyString,
wxEmptyString,
defaultFileName,
wxString(_("FreeFileSync configuration")) + wxT(" (*.ffs_gui)|*.ffs_gui"),
- wxFD_SAVE /*| wxFD_OVERWRITE_PROMPT*/); //creating this on freestore leads to memleak!
+ wxFD_SAVE /*| wxFD_OVERWRITE_PROMPT*/);
if (filePicker.ShowModal() != wxID_OK)
return false;
targetFilename = filePicker.GetPath();
@@ -2200,15 +2217,15 @@ bool MainDialog::trySaveConfig(const wxString* fileName) //return true if saved
try
{
- xmlAccess::writeConfig(guiCfg, targetFilename); //write config to XML
+ xmlAccess::writeConfig(guiCfg, toZ(targetFilename)); //write config to XML
setLastUsedConfig(targetFilename, guiCfg);
pushStatusInformation(_("Configuration saved!"));
return true;
}
- catch (const xmlAccess::FfsXmlError& error)
+ catch (const xmlAccess::FfsXmlError& e)
{
- wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
return false;
}
}
@@ -2220,7 +2237,7 @@ void MainDialog::OnLoadConfig(wxCommandEvent& event)
wxEmptyString,
beforeLast(activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? activeConfigFiles[0] : wxString(), utf8CvrtTo<wxString>(FILE_NAME_SEPARATOR)), //set default dir: empty string if "activeConfigFiles" is empty or has no path separator
wxEmptyString,
- wxString(_("FreeFileSync configuration")) + wxT(" (*.ffs_gui;*.ffs_batch)|*.ffs_gui;*.ffs_batch"),
+ _("FreeFileSync configuration") + L" (*.ffs_gui;*.ffs_batch)|*.ffs_gui;*.ffs_batch",
wxFD_OPEN | wxFD_MULTIPLE);
if (filePicker.ShowModal() == wxID_OK)
@@ -2255,8 +2272,7 @@ void MainDialog::OnLoadFromHistory(wxCommandEvent& event)
std::for_each(selections.begin(), selections.end(),
[&](int pos)
{
- wxClientDataString* cData = dynamic_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(pos));
- if (cData)
+ if (auto cData = dynamic_cast<wxClientDataString*>(m_listBoxHistory->GetClientObject(pos)))
filenames.push_back(cData->name_);
});
@@ -2286,7 +2302,8 @@ bool MainDialog::saveOldConfig() //return false on user abort
bool neverSave = !globalSettings->optDialogs.popupOnConfigChange;
CheckBox cb(_("Never save changes"), neverSave);
- switch (showQuestionDlg(ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO | ReturnQuestionDlg::BUTTON_CANCEL,
+ switch (showQuestionDlg(this,
+ ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO | ReturnQuestionDlg::BUTTON_CANCEL,
_("Save changes to current configuration?"), &cb))
{
case ReturnQuestionDlg::BUTTON_YES:
@@ -2330,7 +2347,7 @@ void MainDialog::loadConfiguration(const std::vector<wxString>& filenames)
try
{
//allow reading batch configurations also
- xmlAccess::convertConfig(filenames, newGuiCfg); //throw (xmlAccess::FfsXmlError)
+ xmlAccess::convertConfig(toZ(filenames), newGuiCfg); //throw FfsXmlError
setLastUsedConfig(filenames, newGuiCfg);
pushStatusInformation(_("Configuration loaded!"));
@@ -2340,11 +2357,11 @@ void MainDialog::loadConfiguration(const std::vector<wxString>& filenames)
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
{
setLastUsedConfig(filenames, xmlAccess::XmlGuiConfig()); //simulate changed config on parsing errors
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING);
+ wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
}
else
{
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
return;
}
}
@@ -2421,9 +2438,7 @@ void MainDialog::onCheckRows(CheckRowsEvent& event)
for (int i = rowFirst; i < rowLast; ++i)
selectedRows.insert(i);
- std::vector<FileSystemObject*> objects;
- gridDataView->getAllFileRef(selectedRows, objects);
-
+ std::vector<FileSystemObject*> objects = gridDataView->getAllFileRef(selectedRows);
setManualFilter(objects, event.setIncluded_);
}
}
@@ -2441,9 +2456,7 @@ void MainDialog::onSetSyncDirection(SyncDirectionEvent& event)
for (int i = rowFirst; i < rowLast; ++i)
selectedRows.insert(i);
- std::vector<FileSystemObject*> objects;
- gridDataView->getAllFileRef(selectedRows, objects);
-
+ std::vector<FileSystemObject*> objects = gridDataView->getAllFileRef(selectedRows);
setSyncDirManually(objects, event.direction_);
}
}
@@ -2469,7 +2482,7 @@ void MainDialog::setLastUsedConfig(const std::vector<wxString>& filenames,
if (activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName())
SetTitle(activeConfigFiles[0]);
else
- SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization"));
+ SetTitle(L"FreeFileSync - " + _("Folder Comparison and Synchronization"));
}
@@ -2556,7 +2569,7 @@ xmlAccess::XmlGuiConfig MainDialog::getConfig() const
const wxString& MainDialog::lastRunConfigName()
{
- static wxString instance = toWx(zen::getConfigDir()) + wxT("LastRun.ffs_gui");
+ static wxString instance = toWx(zen::getConfigDir()) + L"LastRun.ffs_gui";
return instance;
}
@@ -2589,7 +2602,8 @@ void MainDialog::OnHideFilteredButton(wxCommandEvent& event)
void MainDialog::OnConfigureFilter(wxCommandEvent& event)
{
- if (showFilterDialog(true, //is main filter dialog
+ if (showFilterDialog(this,
+ true, //is main filter dialog
currentCfg.mainCfg.globalFilter) == ReturnSmallDlg::BUTTON_OKAY)
{
updateFilterButtons(); //refresh global filter icon
@@ -2718,7 +2732,7 @@ void MainDialog::OnSyncDirNone(wxCommandEvent& event)
inline
wxBitmap buttonPressed(const std::string& name)
{
- wxBitmap background = GlobalResources::getImage(wxT("buttonPressed"));
+ wxBitmap background = GlobalResources::getImage(L"buttonPressed");
return mirrorIfRtl(
layOver(
GlobalResources::getImage(utf8CvrtTo<wxString>(name)), background));
@@ -2740,74 +2754,74 @@ void MainDialog::initViewFilterButtons()
{
//compare result buttons
m_bpButtonLeftOnly->init(buttonPressed("leftOnly"),
- _("Hide files that exist on left side only"),
buttonReleased("leftOnly"),
+ _("Hide files that exist on left side only"),
_("Show files that exist on left side only"));
m_bpButtonRightOnly->init(buttonPressed("rightOnly"),
- _("Hide files that exist on right side only"),
buttonReleased("rightOnly"),
+ _("Hide files that exist on right side only"),
_("Show files that exist on right side only"));
m_bpButtonLeftNewer->init(buttonPressed("leftNewer"),
- _("Hide files that are newer on left"),
buttonReleased("leftNewer"),
+ _("Hide files that are newer on left"),
_("Show files that are newer on left"));
m_bpButtonRightNewer->init(buttonPressed("rightNewer"),
- _("Hide files that are newer on right"),
buttonReleased("rightNewer"),
+ _("Hide files that are newer on right"),
_("Show files that are newer on right"));
m_bpButtonEqual->init(buttonPressed("equal"),
- _("Hide files that are equal"),
buttonReleased("equal"),
+ _("Hide files that are equal"),
_("Show files that are equal"));
m_bpButtonDifferent->init(buttonPressed("different"),
- _("Hide files that are different"),
buttonReleased("different"),
+ _("Hide files that are different"),
_("Show files that are different"));
m_bpButtonConflict->init(buttonPressed("conflict"),
- _("Hide conflicts"),
buttonReleased("conflict"),
+ _("Hide conflicts"),
_("Show conflicts"));
//sync preview buttons
m_bpButtonSyncCreateLeft->init(buttonPressed("createLeft"),
- _("Hide files that will be created on the left side"),
buttonReleased("createLeft"),
+ _("Hide files that will be created on the left side"),
_("Show files that will be created on the left side"));
m_bpButtonSyncCreateRight->init(buttonPressed("createRight"),
- _("Hide files that will be created on the right side"),
buttonReleased("createRight"),
+ _("Hide files that will be created on the right side"),
_("Show files that will be created on the right side"));
m_bpButtonSyncDeleteLeft->init(buttonPressed("deleteLeft"),
- _("Hide files that will be deleted on the left side"),
buttonReleased("deleteLeft"),
+ _("Hide files that will be deleted on the left side"),
_("Show files that will be deleted on the left side"));
m_bpButtonSyncDeleteRight->init(buttonPressed("deleteRight"),
- _("Hide files that will be deleted on the right side"),
buttonReleased("deleteRight"),
+ _("Hide files that will be deleted on the right side"),
_("Show files that will be deleted on the right side"));
m_bpButtonSyncDirOverwLeft->init(buttonPressed("updateLeft"),
- _("Hide files that will be overwritten on left side"),
buttonReleased("updateLeft"),
+ _("Hide files that will be overwritten on left side"),
_("Show files that will be overwritten on left side"));
m_bpButtonSyncDirOverwRight->init(buttonPressed("updateRight"),
- _("Hide files that will be overwritten on right side"),
buttonReleased("updateRight"),
+ _("Hide files that will be overwritten on right side"),
_("Show files that will be overwritten on right side"));
m_bpButtonSyncDirNone->init(buttonPressed("none"),
- _("Hide files that won't be copied"),
buttonReleased("none"),
+ _("Hide files that won't be copied"),
_("Show files that won't be copied"));
//compare result buttons
@@ -2877,11 +2891,15 @@ void MainDialog::OnCompare(wxCommandEvent& event)
const std::vector<zen::FolderPairCfg> cmpConfig = zen::extractCompareCfg(getConfig().mainCfg);
//GUI mode: place directory locks on directories isolated(!) during both comparison and synchronization
- LockHolder dummy2(true); //allow pw prompt
- for (std::vector<FolderPairCfg>::const_iterator i = cmpConfig.begin(); i != cmpConfig.end(); ++i)
+ std::unique_ptr<LockHolder> dummy2;
+ if (globalSettings->createLockFile)
{
- dummy2.addDir(i->leftDirectoryFmt, statusHandler);
- dummy2.addDir(i->rightDirectoryFmt, statusHandler);
+ dummy2.reset(new LockHolder(true)); //allow pw prompt
+ for (auto iter = cmpConfig.begin(); iter != cmpConfig.end(); ++iter)
+ {
+ dummy2->addDir(iter->leftDirectoryFmt, statusHandler);
+ dummy2->addDir(iter->rightDirectoryFmt, statusHandler);
+ }
}
//begin comparison
@@ -2975,7 +2993,8 @@ void MainDialog::OnSyncSettings(wxCommandEvent& event)
globalSettings->gui.onCompletionHistoryMax
};
- if (showSyncConfigDlg(currentCfg.mainCfg.cmpConfig.compareVar,
+ if (showSyncConfigDlg(this,
+ currentCfg.mainCfg.cmpConfig.compareVar,
currentCfg.mainCfg.syncCfg,
&currentCfg.handleError,
&ewfCfg) == ReturnSyncConfig::BUTTON_OKAY) //optional input parameter
@@ -3020,7 +3039,7 @@ void MainDialog::OnCmpSettings(wxCommandEvent& event)
CompConfig cmpConfigNew = currentCfg.mainCfg.cmpConfig;
- if (zen::showCompareCfgDialog(cmpConfigNew) == ReturnSmallDlg::BUTTON_OKAY &&
+ if (zen::showCompareCfgDialog(this, cmpConfigNew) == ReturnSmallDlg::BUTTON_OKAY &&
//check if settings were changed at all
cmpConfigNew != currentCfg.mainCfg.cmpConfig)
{
@@ -3050,10 +3069,10 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
{
bool dontShowAgain = false;
- if (zen::showSyncPreviewDlg(
- getConfig().mainCfg.getSyncVariantName(),
- zen::SyncStatistics(folderCmp),
- dontShowAgain) != ReturnSmallDlg::BUTTON_OKAY)
+ if (zen::showSyncPreviewDlg(this,
+ getConfig().mainCfg.getSyncVariantName(),
+ zen::SyncStatistics(folderCmp),
+ dontShowAgain) != ReturnSmallDlg::BUTTON_OKAY)
return;
globalSettings->optDialogs.showSummaryBeforeSync = !dontShowAgain;
@@ -3078,12 +3097,15 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
globalSettings->gui.onCompletionHistory);
//GUI mode: place directory locks on directories isolated(!) during both comparison and synchronization
- LockHolder dummy2(true); //allow pw prompt
-
- for (auto iter = begin(folderCmp); iter != end(folderCmp); ++iter)
+ std::unique_ptr<LockHolder> dummy2;
+ if (globalSettings->createLockFile)
{
- dummy2.addDir(iter->getBaseDirPf<LEFT_SIDE >(), statusHandler);
- dummy2.addDir(iter->getBaseDirPf<RIGHT_SIDE>(), statusHandler);
+ dummy2.reset(new LockHolder(true)); //allow pw prompt
+ for (auto iter = begin(folderCmp); iter != end(folderCmp); ++iter)
+ {
+ dummy2->addDir(iter->getBaseDirPf<LEFT_SIDE >(), statusHandler);
+ dummy2->addDir(iter->getBaseDirPf<RIGHT_SIDE>(), statusHandler);
+ }
}
//start synchronization and mark all elements processed
@@ -3104,7 +3126,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
syncProc.startSynchronizationProcess(syncProcessCfg, folderCmp);
//play (optional) sound notification after sync has completed (GUI and batch mode)
- const wxString soundFile = toWx(zen::getResourceDir()) + wxT("Sync_Complete.wav");
+ const wxString soundFile = toWx(zen::getResourceDir()) + L"Sync_Complete.wav";
if (fileExists(toZ(soundFile)))
wxSound::Play(soundFile, wxSOUND_ASYNC);
}
@@ -3411,7 +3433,8 @@ void MainDialog::applySyncConfig()
if (warningActive)
{
bool dontWarnAgain = false;
- if (showWarningDlg(ReturnWarningDlg::BUTTON_IGNORE, warning, dontWarnAgain) == ReturnWarningDlg::BUTTON_IGNORE)
+ if (showWarningDlg(this,
+ ReturnWarningDlg::BUTTON_IGNORE, warning, dontWarnAgain) == ReturnWarningDlg::BUTTON_IGNORE)
warningActive = !dontWarnAgain;
}
});
@@ -3652,146 +3675,151 @@ void MainDialog::clearAddFolderPairs()
//menu events
void MainDialog::OnMenuGlobalSettings(wxCommandEvent& event)
{
- zen::showGlobalSettingsDlg(*globalSettings);
+ zen::showGlobalSettingsDlg(this, *globalSettings);
}
void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
{
//get a filename
- const wxString defaultFileName = wxT("FileList.csv"); //proposal
+ const wxString defaultFileName = L"FileList.csv"; //proposal
wxFileDialog filePicker(this,
wxEmptyString,
wxEmptyString,
defaultFileName,
- wxString(_("Comma separated list")) + wxT(" (*.csv)|*.csv"),
+ _("Comma separated list") + L" (*.csv)|*.csv",
wxFD_SAVE /*| wxFD_OVERWRITE_PROMPT*/); //creating this on freestore leads to memleak!
- if (filePicker.ShowModal() == wxID_OK)
+ if (filePicker.ShowModal() != wxID_OK)
+ return;
+
+ const wxString newFileName = 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;
+
+ //write legend
+ exportString += utf8CvrtTo<UtfString>(_("Legend")) + '\n';
+ if (syncPreviewEnabled)
{
- const wxString newFileName = filePicker.GetPath();
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_EQUAL)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_EQUAL)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_CREATE_NEW_LEFT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_CREATE_NEW_LEFT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_CREATE_NEW_RIGHT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_CREATE_NEW_RIGHT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_OVERWRITE_LEFT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_OVERWRITE_LEFT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_OVERWRITE_RIGHT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_OVERWRITE_RIGHT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_DELETE_LEFT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_DELETE_LEFT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_DELETE_RIGHT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_DELETE_RIGHT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_DO_NOTHING)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_DO_NOTHING)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getSyncOpDescription(SO_UNRESOLVED_CONFLICT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(SO_UNRESOLVED_CONFLICT)) + '\n';
+ }
+ else
+ {
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_EQUAL)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_EQUAL)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_DIFFERENT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_DIFFERENT)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_LEFT_SIDE_ONLY)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_LEFT_SIDE_ONLY)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_RIGHT_SIDE_ONLY)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_RIGHT_SIDE_ONLY)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_LEFT_NEWER)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_LEFT_NEWER)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_RIGHT_NEWER)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_RIGHT_NEWER)) + '\n';
+ exportString += "\"" + utf8CvrtTo<UtfString>(getCategoryDescription(FILE_CONFLICT)) + "\";" + utf8CvrtTo<UtfString>(getSymbol(FILE_CONFLICT)) + '\n';
+ }
+ exportString += '\n';
- zxString exportString; //perf: wxString doesn't model exponential growth and so is out
+ //base folders
+ exportString += utf8CvrtTo<UtfString>(_("Folder pairs")) + '\n' ;
+ std::for_each(begin(folderCmp), end(folderCmp),
+ [&](BaseDirMapping& baseMap)
+ {
+ exportString += utf8CvrtTo<UtfString>(baseMap.getBaseDirPf<LEFT_SIDE >()) + ';';
+ exportString += utf8CvrtTo<UtfString>(baseMap.getBaseDirPf<RIGHT_SIDE>()) + '\n';
+ });
+ exportString += '\n';
- //write legend
- exportString += copyStringTo<zxString>(_("Legend")) + wxT('\n');
- if (syncPreviewEnabled)
- {
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_EQUAL)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_EQUAL)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_CREATE_NEW_LEFT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_CREATE_NEW_LEFT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_CREATE_NEW_RIGHT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_CREATE_NEW_RIGHT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_OVERWRITE_LEFT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_OVERWRITE_LEFT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_OVERWRITE_RIGHT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_OVERWRITE_RIGHT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_DELETE_LEFT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_DELETE_LEFT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_DELETE_RIGHT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_DELETE_RIGHT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_DO_NOTHING)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_DO_NOTHING)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getSyncOpDescription(SO_UNRESOLVED_CONFLICT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(SO_UNRESOLVED_CONFLICT)) + wxT('\n');
- }
- else
- {
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_EQUAL)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_EQUAL)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_DIFFERENT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_DIFFERENT)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_LEFT_SIDE_ONLY)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_LEFT_SIDE_ONLY)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_RIGHT_SIDE_ONLY)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_RIGHT_SIDE_ONLY)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_LEFT_NEWER)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_LEFT_NEWER)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_RIGHT_NEWER)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_RIGHT_NEWER)) + wxT('\n');
- exportString += wxT("\"") + copyStringTo<zxString>(getCategoryDescription(FILE_CONFLICT)) + wxT("\";") + copyStringTo<zxString>(getSymbol(FILE_CONFLICT)) + wxT('\n');
- }
- exportString += wxT('\n');
+ //write header
+ auto provLeft = m_gridMain->getDataProvider(gridview::COMP_LEFT);
+ auto provMiddle = m_gridMain->getDataProvider(gridview::COMP_MIDDLE);
+ auto provRight = m_gridMain->getDataProvider(gridview::COMP_RIGHT);
- auto addCellValue = [&](const wxString& val)
- {
- if (val.find(wxT(';')) != wxString::npos)
- exportString += wxT('\"') + copyStringTo<zxString>(val) + wxT('\"');
- else
- exportString += copyStringTo<zxString>(val);
- };
+ auto colAttrLeft = m_gridMain->getColumnConfig(gridview::COMP_LEFT);
+ auto colAttrMiddle = m_gridMain->getColumnConfig(gridview::COMP_MIDDLE);
+ auto colAttrRight = m_gridMain->getColumnConfig(gridview::COMP_RIGHT);
- //write header
- auto provLeft = m_gridMain->getDataProvider(gridview::COMP_LEFT);
- auto provMiddle = m_gridMain->getDataProvider(gridview::COMP_MIDDLE);
- auto provRight = m_gridMain->getDataProvider(gridview::COMP_RIGHT);
+ vector_remove_if(colAttrLeft , [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
+ vector_remove_if(colAttrMiddle, [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
+ vector_remove_if(colAttrRight , [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
- auto colAttrLeft = m_gridMain->getColumnConfig(gridview::COMP_LEFT);
- auto colAttrMiddle = m_gridMain->getColumnConfig(gridview::COMP_MIDDLE);
- auto colAttrRight = m_gridMain->getColumnConfig(gridview::COMP_RIGHT);
+ auto addCellValue = [&](const wxString& val)
+ {
+ if (val.find(L';') != wxString::npos)
+ exportString += '\"' + utf8CvrtTo<UtfString>(val) + '\"';
+ else
+ exportString += utf8CvrtTo<UtfString>(val);
+ };
- vector_remove_if(colAttrLeft , [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
- vector_remove_if(colAttrMiddle, [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
- vector_remove_if(colAttrRight , [](const Grid::ColumnAttribute& ca) { return !ca.visible_; });
+ if (provLeft && provMiddle && provRight)
+ {
+ std::for_each(colAttrLeft.begin(), colAttrLeft.end(),
+ [&](const Grid::ColumnAttribute& ca)
+ {
+ addCellValue(provLeft->getColumnLabel(ca.type_));
+ exportString += ';';
+ });
+ std::for_each(colAttrMiddle.begin(), colAttrMiddle.end(),
+ [&](const Grid::ColumnAttribute& ca)
+ {
+ addCellValue(provMiddle->getColumnLabel(ca.type_));
+ exportString += ';';
+ });
+ if (!colAttrRight.empty())
+ {
+ std::for_each(colAttrRight.begin(), colAttrRight.end() - 1,
+ [&](const Grid::ColumnAttribute& ca)
+ {
+ addCellValue(provRight->getColumnLabel(ca.type_));
+ exportString += ';';
+ });
+ addCellValue(provRight->getColumnLabel(colAttrRight.back().type_));
+ }
+ exportString += '\n';
- if (provLeft && provMiddle && provRight)
+ //main grid
+ const size_t rowCount = m_gridMain->getRowCount();
+ for (size_t row = 0; row < rowCount; ++row)
{
std::for_each(colAttrLeft.begin(), colAttrLeft.end(),
[&](const Grid::ColumnAttribute& ca)
{
- addCellValue(provLeft->getColumnLabel(ca.type_));
- exportString += L';';
+ addCellValue(provLeft->getValue(row, ca.type_));
+ exportString += ';';
});
std::for_each(colAttrMiddle.begin(), colAttrMiddle.end(),
[&](const Grid::ColumnAttribute& ca)
{
- addCellValue(provMiddle->getColumnLabel(ca.type_));
- exportString += L';';
+ addCellValue(provMiddle->getValue(row, ca.type_));
+ exportString += ';';
});
if (!colAttrRight.empty())
{
std::for_each(colAttrRight.begin(), colAttrRight.end() - 1,
[&](const Grid::ColumnAttribute& ca)
{
- addCellValue(provRight->getColumnLabel(ca.type_));
- exportString += L';';
- });
- addCellValue(provRight->getColumnLabel(colAttrRight.back().type_));
- }
- exportString += L'\n';
-
- //main grid
- const size_t rowCount = m_gridMain->getRowCount();
- for (size_t row = 0; row < rowCount; ++row)
- {
- std::for_each(colAttrLeft.begin(), colAttrLeft.end(),
- [&](const Grid::ColumnAttribute& ca)
- {
- addCellValue(provLeft->getValue(row, ca.type_));
- exportString += L';';
+ addCellValue(provRight->getValue(row, ca.type_));
+ exportString += ';';
});
- std::for_each(colAttrMiddle.begin(), colAttrMiddle.end(),
- [&](const Grid::ColumnAttribute& ca)
- {
- addCellValue(provMiddle->getValue(row, ca.type_));
- exportString += L';';
- });
- if (!colAttrRight.empty())
- {
- std::for_each(colAttrRight.begin(), colAttrRight.end() - 1,
- [&](const Grid::ColumnAttribute& ca)
- {
- addCellValue(provRight->getValue(row, ca.type_));
- exportString += L';';
- });
- addCellValue(provRight->getValue(row, colAttrRight.back().type_));
- }
- exportString += L'\n';
+ addCellValue(provRight->getValue(row, colAttrRight.back().type_));
}
+ exportString += '\n';
+ }
- //write export file
- wxFFile output(newFileName.c_str(), wxT("w")); //don't write in binary mode
- if (output.IsOpened())
- {
- //generate UTF8 representation
- size_t bufferSize = 0;
- const wxCharBuffer utf8buffer = wxConvUTF8.cWC2MB(exportString.c_str(), exportString.size(), &bufferSize);
-
- output.Write(BYTE_ORDER_MARK_UTF8, sizeof(BYTE_ORDER_MARK_UTF8) - 1);
- output.Write(utf8buffer, bufferSize);
- pushStatusInformation(_("File list exported!"));
- }
- else
- {
- wxMessageBox(wxString(_("Error writing file:")) + wxT(" \"") + newFileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
- }
+ //write export file
+ wxFFile output(newFileName.c_str(), L"w"); //don't write in binary mode
+ if (output.IsOpened())
+ {
+ output.Write(BYTE_ORDER_MARK_UTF8, sizeof(BYTE_ORDER_MARK_UTF8) - 1);
+ output.Write(exportString.c_str(), exportString.size());
+ pushStatusInformation(_("File list exported!"));
}
+ else
+ wxMessageBox(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(toZ(newFileName))), _("Error"), wxOK | wxICON_ERROR, this);
}
}
@@ -3803,9 +3831,10 @@ void MainDialog::OnMenuBatchJob(wxCommandEvent& event)
const wxString referenceFile = activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() ? activeConfigFiles[0] : wxString();
- const xmlAccess::XmlBatchConfig batchCfg = convertGuiToBatch(currCfg, referenceFile);
+ const xmlAccess::XmlBatchConfig batchCfg = convertGuiToBatch(currCfg, toZ(referenceFile));
- showSyncBatchDlg(referenceFile, batchCfg,
+ showSyncBatchDlg(this,
+ referenceFile, batchCfg,
folderHistoryLeft,
folderHistoryRight,
globalSettings->gui.onCompletionHistory,
@@ -3815,7 +3844,7 @@ void MainDialog::OnMenuBatchJob(wxCommandEvent& event)
void MainDialog::OnMenuCheckVersion(wxCommandEvent& event)
{
- zen::checkForUpdateNow();
+ zen::checkForUpdateNow(this);
}
@@ -3824,7 +3853,7 @@ void MainDialog::OnRegularUpdateCheck(wxIdleEvent& event)
//execute just once per startup!
Disconnect(wxEVT_IDLE, wxIdleEventHandler(MainDialog::OnRegularUpdateCheck), nullptr, this);
- zen::checkForUpdatePeriodically(globalSettings->gui.lastUpdateCheck);
+ zen::checkForUpdatePeriodically(this, globalSettings->gui.lastUpdateCheck);
}
@@ -3847,7 +3876,7 @@ void MainDialog::OnLayoutWindowAsync(wxIdleEvent& event)
void MainDialog::OnMenuAbout(wxCommandEvent& event)
{
- zen::showAboutDialog();
+ zen::showAboutDialog(this);
}
diff --git a/ui/main_dlg.h b/ui/main_dlg.h
index 228cef4a..6c0c6974 100644
--- a/ui/main_dlg.h
+++ b/ui/main_dlg.h
@@ -184,6 +184,7 @@ private:
void updateGuiAfterFilterChange(int delay);
void excludeExtension(const Zstring& extension);
+ void excludeShortname(const zen::FileSystemObject& fsObj);
void excludeItems(const std::vector<zen::FileSystemObject*>& selection);
void updateStatistics();
diff --git a/ui/msg_popup.cpp b/ui/msg_popup.cpp
index 1ed892f8..b6067242 100644
--- a/ui/msg_popup.cpp
+++ b/ui/msg_popup.cpp
@@ -16,7 +16,7 @@ using namespace zen;
class ErrorDlg : public ErrorDlgGenerated
{
public:
- ErrorDlg(wxWindow* parentWindow,
+ ErrorDlg(wxWindow* parent,
int activeButtons,
const wxString& messageText,
bool* ignoreNextErrors);
@@ -31,15 +31,15 @@ private:
};
-ErrorDlg::ErrorDlg(wxWindow* parentWindow, const int activeButtons, const wxString& messageText, bool* ignoreNextErrors) :
- ErrorDlgGenerated(parentWindow),
+ErrorDlg::ErrorDlg(wxWindow* parent, const int activeButtons, const wxString& messageText, bool* ignoreNextErrors) :
+ ErrorDlgGenerated(parent),
ignoreErrors(ignoreNextErrors)
{
#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(wxT("error")));
+ m_bitmap10->SetBitmap(GlobalResources::getImage(L"error"));
m_textCtrl8->SetValue(messageText);
if (ignoreNextErrors)
@@ -96,9 +96,9 @@ void ErrorDlg::OnAbort(wxCommandEvent& event)
}
-ReturnErrorDlg::ButtonPressed zen::showErrorDlg(int activeButtons, const wxString& messageText, bool* ignoreNextErrors)
+ReturnErrorDlg::ButtonPressed zen::showErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors)
{
- ErrorDlg errorDlg(nullptr, activeButtons, messageText, ignoreNextErrors);
+ ErrorDlg errorDlg(parent, activeButtons, messageText, ignoreNextErrors);
errorDlg.Raise();
return static_cast<ReturnErrorDlg::ButtonPressed>(errorDlg.ShowModal());
}
@@ -108,7 +108,7 @@ ReturnErrorDlg::ButtonPressed zen::showErrorDlg(int activeButtons, const wxStrin
class WarningDlg : public WarningDlgGenerated
{
public:
- WarningDlg(wxWindow* parentWindow, int activeButtons, const wxString& messageText, bool& dontShowAgain);
+ WarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain);
private:
void OnClose(wxCloseEvent& event);
@@ -119,15 +119,15 @@ private:
};
-WarningDlg::WarningDlg(wxWindow* parentWindow, int activeButtons, const wxString& messageText, bool& dontShowDlgAgain) :
- WarningDlgGenerated(parentWindow),
+WarningDlg::WarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowDlgAgain) :
+ WarningDlgGenerated(parent),
dontShowAgain(dontShowDlgAgain)
{
#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(wxT("warning")));
+ m_bitmap10->SetBitmap(GlobalResources::getImage(L"warning"));
m_textCtrl8->SetValue(messageText);
m_checkBoxDontShowAgain->SetValue(dontShowAgain);
@@ -178,9 +178,9 @@ void WarningDlg::OnAbort(wxCommandEvent& event)
}
-ReturnWarningDlg::ButtonPressed zen::showWarningDlg(int activeButtons, const wxString& messageText, bool& dontShowAgain)
+ReturnWarningDlg::ButtonPressed zen::showWarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain)
{
- WarningDlg warningDlg(nullptr, activeButtons, messageText, dontShowAgain);
+ WarningDlg warningDlg(parent, activeButtons, messageText, dontShowAgain);
warningDlg.Raise();
return static_cast<ReturnWarningDlg::ButtonPressed>(warningDlg.ShowModal());
}
@@ -190,7 +190,7 @@ ReturnWarningDlg::ButtonPressed zen::showWarningDlg(int activeButtons, const wxS
class QuestionDlg : public QuestionDlgGenerated
{
public:
- QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxString& messageText, CheckBox* checkbox);
+ QuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox);
private:
void OnClose (wxCloseEvent& event) { EndModal(ReturnQuestionDlg::BUTTON_CANCEL); }
@@ -202,8 +202,8 @@ private:
};
-QuestionDlg::QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxString& messageText, CheckBox* checkbox) :
- QuestionDlgGenerated(parentWindow),
+QuestionDlg::QuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox) :
+ QuestionDlgGenerated(parent),
checkbox_(checkbox)
{
#ifdef FFS_WIN
@@ -253,9 +253,9 @@ void QuestionDlg::OnNo(wxCommandEvent& event)
EndModal(ReturnQuestionDlg::BUTTON_NO);
}
-ReturnQuestionDlg::ButtonPressed zen::showQuestionDlg(int activeButtons, const wxString& messageText, CheckBox* checkbox)
+ReturnQuestionDlg::ButtonPressed zen::showQuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox)
{
- QuestionDlg qtnDlg(nullptr, activeButtons, messageText, checkbox);
+ QuestionDlg qtnDlg(parent, activeButtons, messageText, checkbox);
qtnDlg.Raise();
return static_cast<ReturnQuestionDlg::ButtonPressed>(qtnDlg.ShowModal());
}
diff --git a/ui/msg_popup.h b/ui/msg_popup.h
index ccdf09e4..19a3c84f 100644
--- a/ui/msg_popup.h
+++ b/ui/msg_popup.h
@@ -7,10 +7,14 @@
#ifndef MESSAGEPOPUP_H_INCLUDED
#define MESSAGEPOPUP_H_INCLUDED
+#include <wx/window.h>
#include <wx/string.h>
+
namespace zen
{
+//parent window, optional: support correct dialog placement above parent on multiple monitor systems
+
struct ReturnErrorDlg
{
enum ButtonPressed
@@ -20,7 +24,7 @@ struct ReturnErrorDlg
BUTTON_ABORT = 4
};
};
-ReturnErrorDlg::ButtonPressed showErrorDlg(int activeButtons, const wxString& messageText, bool* ignoreNextErrors); //ignoreNextErrors may be nullptr
+ReturnErrorDlg::ButtonPressed showErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors); //ignoreNextErrors may be nullptr
struct ReturnWarningDlg
@@ -32,7 +36,7 @@ struct ReturnWarningDlg
BUTTON_ABORT = 4
};
};
-ReturnWarningDlg::ButtonPressed showWarningDlg(int activeButtons, const wxString& messageText, bool& dontShowAgain);
+ReturnWarningDlg::ButtonPressed showWarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain);
struct ReturnQuestionDlg
@@ -53,8 +57,7 @@ struct CheckBox
bool& value_; //in/out
};
-ReturnQuestionDlg::ButtonPressed showQuestionDlg(int activeButtons, const wxString& messageText, CheckBox* checkbox = nullptr);
+ReturnQuestionDlg::ButtonPressed showQuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox = nullptr);
}
-
#endif // MESSAGEPOPUP_H_INCLUDED
diff --git a/ui/progress_indicator.cpp b/ui/progress_indicator.cpp
index 1e4be39a..fba2c801 100644
--- a/ui/progress_indicator.cpp
+++ b/ui/progress_indicator.cpp
@@ -6,20 +6,19 @@
#include "progress_indicator.h"
#include <memory>
-#include <zen/basic_math.h>
#include <wx/imaglist.h>
#include <wx/stopwatch.h>
#include <wx/wupdlock.h>
+#include <zen/basic_math.h>
#include <wx+/mouse_move_dlg.h>
#include <wx+/toggle_button.h>
-#include <wx+/string_conv.h>
#include <wx+/format_unit.h>
#include <wx+/image_tools.h>
#include <wx+/graph.h>
#include <wx+/no_flicker.h>
#include "gui_generated.h"
#include "../lib/resources.h"
-#include "../lib/statistics.h"
+#include "../lib/perf_check.h"
#include "tray_icon.h"
#include "taskbar.h"
#include "exec_finished_box.h"
@@ -32,8 +31,8 @@ namespace
const int GAUGE_FULL_RANGE = 50000;
//window size used for statistics in milliseconds
-const int windowSizeRemainingTime = 60000; //some usecases have dropouts of 40 seconds -> 60 sec. window size handles them well
-const int windowSizeBytesPerSec = 5000; //
+const int WINDOW_REMAINING_TIME = 60000; //some usecases have dropouts of 40 seconds -> 60 sec. window size handles them well
+const int WINDOW_BYTES_PER_SEC = 5000; //
}
@@ -42,49 +41,24 @@ class CompareStatus::CompareStatusImpl : public CompareStatusGenerated
public:
CompareStatusImpl(wxTopLevelWindow& parentWindow);
- void init(); //constructor/destructor semantics, but underlying Window is reused
+ void init(const Statistics& syncStat); //constructor/destructor semantics, but underlying Window is reused
void finalize(); //
- void switchToCompareBytewise(int totalObjectsToProcess, Int64 totalDataToProcess);
- void incScannedObjects_NoUpdate(int number);
- void incProcessedCmpData_NoUpdate(int objectsProcessed, Int64 dataProcessed);
- void incTotalCmpData_NoUpdate (int objectsProcessed, Int64 dataProcessed);
-
- void setStatusText_NoUpdate(const wxString& text);
+ void switchToCompareBytewise();
void updateStatusPanelNow();
private:
wxTopLevelWindow& parentWindow_;
wxString titleTextBackup;
- //status variables
- size_t scannedObjects;
- wxString currentStatusText;
-
wxStopWatch timeElapsed;
- //gauge variables
- int totalObjects; //file/dir/symlink/operation count
- Int64 totalData; //unit: [bytes]
- int currentObjects;
- Int64 currentData;
-
- void showProgressExternally(const wxString& progressText, double fraction = 0); //between [0, 1]
-
- enum CurrentStatus
- {
- SCANNING,
- COMPARING_CONTENT,
- };
-
- CurrentStatus status;
+ const Statistics* syncStat_; //only bound while sync is running
std::unique_ptr<Taskbar> taskbar_;
+ std::unique_ptr<PerfCheck> perf; //estimate remaining time
- //remaining time
- std::unique_ptr<Statistics> statistics;
-
- long lastStatCallSpeed; //used for calculating intervals between statistics update
+ long lastStatCallSpeed; //used for calculating intervals between showing and collecting perf samples
long lastStatCallRemTime; //
};
@@ -92,21 +66,17 @@ private:
CompareStatus::CompareStatusImpl::CompareStatusImpl(wxTopLevelWindow& parentWindow) :
CompareStatusGenerated(&parentWindow),
parentWindow_(parentWindow),
- scannedObjects(0),
- totalObjects(0),
- totalData(0),
- currentObjects(0),
- currentData(0),
- status(SCANNING),
- lastStatCallSpeed(-1000000), //some big number
+ syncStat_(nullptr),
+ lastStatCallSpeed (-1000000), //some big number
lastStatCallRemTime(-1000000)
{
- init();
+ //init(); -> needed?
}
-void CompareStatus::CompareStatusImpl::init()
+void CompareStatus::CompareStatusImpl::init(const Statistics& syncStat)
{
+ syncStat_ = &syncStat;
titleTextBackup = parentWindow_.GetTitle();
try //try to get access to Windows 7/Ubuntu taskbar
@@ -115,65 +85,47 @@ void CompareStatus::CompareStatusImpl::init()
}
catch (const TaskbarNotAvailable&) {}
- status = SCANNING;
-
//initialize gauge
m_gauge2->SetRange(GAUGE_FULL_RANGE);
m_gauge2->SetValue(0);
+ perf.reset();
+ timeElapsed.Start(); //measure total time
+
//initially hide status that's relevant for comparing bytewise only
bSizerFilesFound ->Show(true);
bSizerFilesRemaining->Show(false);
sSizerSpeed ->Show(false);
sSizerTimeRemaining ->Show(false);
- m_gauge2->Hide();
- bSizer42->Layout();
-
- scannedObjects = 0;
- currentStatusText.clear();
-
- totalObjects = 0;
- totalData = 0;
- currentObjects = 0;
- currentData = 0;
-
- statistics.reset();
-
- timeElapsed.Start(); //measure total time
-
updateStatusPanelNow();
+ m_gauge2->Hide();
+ bSizer42->Layout();
Layout();
}
void CompareStatus::CompareStatusImpl::finalize()
{
- taskbar_.reset();
+ syncStat_ = nullptr;
parentWindow_.SetTitle(titleTextBackup);
+ taskbar_.reset();
}
-void CompareStatus::CompareStatusImpl::switchToCompareBytewise(int totalObjectsToProcess, Int64 totalDataToProcess)
+void CompareStatus::CompareStatusImpl::switchToCompareBytewise()
{
- status = COMPARING_CONTENT;
-
- currentData = 0;
- currentObjects = 0;
- totalData = totalDataToProcess;
- totalObjects = totalObjectsToProcess;
-
- //set new statistics handler: 10 seconds "window" for remaining time, 5 seconds for speed
- statistics.reset(new Statistics(totalObjectsToProcess, to<double>(totalDataToProcess), windowSizeRemainingTime, windowSizeBytesPerSec));
+ //start to measure perf
+ perf.reset(new PerfCheck(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC));
lastStatCallSpeed = -1000000; //some big number
lastStatCallRemTime = -1000000;
//show status for comparing bytewise
- bSizerFilesFound->Show(false);
+ bSizerFilesFound ->Show(false);
bSizerFilesRemaining->Show(true);
- sSizerSpeed->Show(true);
- sSizerTimeRemaining->Show(true);
+ sSizerSpeed ->Show(true);
+ sSizerTimeRemaining ->Show(true);
m_gauge2->Show();
bSizer42->Layout();
@@ -181,154 +133,119 @@ void CompareStatus::CompareStatusImpl::switchToCompareBytewise(int totalObjectsT
}
-void CompareStatus::CompareStatusImpl::incScannedObjects_NoUpdate(int number)
-{
- scannedObjects += number;
-}
-
-
-void CompareStatus::CompareStatusImpl::incProcessedCmpData_NoUpdate(int objectsDelta, Int64 dataDelta)
-{
- currentData += dataDelta;
- currentObjects += objectsDelta;
-}
-
-
-void CompareStatus::CompareStatusImpl::incTotalCmpData_NoUpdate(int objectsDelta, Int64 dataDelta)
-{
- totalData += dataDelta;
- totalObjects += objectsDelta;
-
- if (statistics)
- statistics->setNewTotal(totalObjects, to<double>(totalData));
-}
-
-
-void CompareStatus::CompareStatusImpl::setStatusText_NoUpdate(const wxString& text)
+void CompareStatus::CompareStatusImpl::updateStatusPanelNow()
{
- currentStatusText = text;
-}
+ if (!syncStat_) //no comparison running!!
+ return;
+ //wxWindowUpdateLocker dummy(this) -> not needed
-void CompareStatus::CompareStatusImpl::showProgressExternally(const wxString& progressText, double fraction)
-{
- if (parentWindow_.GetTitle() != progressText)
- parentWindow_.SetTitle(progressText);
+ const wxString& scannedObjects = toStringSep(syncStat_->getObjectsCurrent(ProcessCallback::PHASE_SCANNING));
- //show progress on Windows 7 taskbar
+ auto setTitle = [&](const wxString& title)
+ {
+ if (parentWindow_.GetTitle() != title)
+ parentWindow_.SetTitle(title);
+ };
- if (taskbar_.get())
- switch (status)
- {
- case SCANNING:
- taskbar_->setStatus(Taskbar::STATUS_INDETERMINATE);
- break;
- case COMPARING_CONTENT:
- taskbar_->setProgress(fraction);
- taskbar_->setStatus(Taskbar::STATUS_NORMAL);
- break;
- }
-}
+ bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
+ //status texts
+ setText(*m_textCtrlStatus, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts!
-void CompareStatus::CompareStatusImpl::updateStatusPanelNow()
-{
- //static RetrieveStatistics statistic;
- //statistic.writeEntry(currentData.ToDouble(), currentObjects);
+ //write status information to taskbar, parent title ect.
+ switch (syncStat_->currentPhase())
{
- //wxWindowUpdateLocker dummy(this) -> not needed
-
- //add both data + obj-count, to handle "deletion-only" cases
- const double fraction = totalData + totalObjects == 0 ? 0 : std::max(0.0, to<double>(currentData + currentObjects) / to<double>(totalData + totalObjects));
+ case ProcessCallback::PHASE_NONE:
+ case ProcessCallback::PHASE_SCANNING:
+ //dialog caption, taskbar
+ setTitle(scannedObjects + L" - " + _("Scanning..."));
+ if (taskbar_.get()) //support Windows 7 taskbar
+ taskbar_->setStatus(Taskbar::STATUS_INDETERMINATE);
+ break;
- //write status information to taskbar, parent title ect.
- switch (status)
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
{
- case SCANNING:
- showProgressExternally(toStringSep(scannedObjects) + wxT(" - ") + _("Scanning..."));
- break;
- case COMPARING_CONTENT:
- showProgressExternally(fractionToShortString(fraction) + wxT(" - ") + _("Comparing content..."), fraction);
- break;
- }
+ auto objectsCurrent = syncStat_->getObjectsCurrent(ProcessCallback::PHASE_COMPARING_CONTENT);
+ auto objectsTotal = syncStat_->getObjectsTotal (ProcessCallback::PHASE_COMPARING_CONTENT);
+ auto dataCurrent = syncStat_->getDataCurrent (ProcessCallback::PHASE_COMPARING_CONTENT);
+ auto dataTotal = syncStat_->getDataTotal (ProcessCallback::PHASE_COMPARING_CONTENT);
- bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
+ //add both data + obj-count, to handle "deletion-only" cases
+ const double fraction = dataTotal + objectsTotal == 0 ? 0 : std::max(0.0, to<double>(dataCurrent + objectsCurrent) / to<double>(dataTotal + objectsTotal));
- //remove linebreaks from currentStatusText
- wxString statusTextFmt = currentStatusText;
- replace(statusTextFmt, L'\n', L' ');
+ //dialog caption, taskbar
+ setTitle(fractionToShortString(fraction) + wxT(" - ") + _("Comparing content..."));
+ if (taskbar_.get())
+ {
+ taskbar_->setProgress(fraction);
+ taskbar_->setStatus(Taskbar::STATUS_NORMAL);
+ }
- //status texts
- if (m_textCtrlStatus->GetValue() != statusTextFmt) //no layout update for status texts!
- m_textCtrlStatus->ChangeValue(statusTextFmt);
+ //progress indicator, shown for binary comparison only
+ m_gauge2->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE));
- //nr of scanned objects
- setText(*m_staticTextScanned, toStringSep(scannedObjects), &layoutChanged);
+ //remaining objects and bytes for file comparison
+ setText(*m_staticTextFilesRemaining, toStringSep(objectsTotal - objectsCurrent), &layoutChanged);
+ setText(*m_staticTextDataRemaining, L"(" + filesizeToShortString(dataTotal - dataCurrent) + L")", &layoutChanged);
- //progress indicator for "compare file content"
- m_gauge2->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE));
+ //remaining time and speed: only visible during binary comparison
+ if (perf)
+ if (timeElapsed.Time() - lastStatCallSpeed >= 500) //-> Win 7 copy uses 1 sec update interval
+ {
+ lastStatCallSpeed = timeElapsed.Time();
- //remaining files left for file comparison
- const wxString filesToCompareTmp = toStringSep(totalObjects - currentObjects);
- setText(*m_staticTextFilesRemaining, filesToCompareTmp, &layoutChanged);
+ perf->addSample(objectsCurrent, to<double>(dataCurrent), timeElapsed.Time());
- //remaining bytes left for file comparison
- const wxString remainingBytesTmp = zen::filesizeToShortString(totalData - currentData);
- setText(*m_staticTextDataRemaining, remainingBytesTmp, &layoutChanged);
+ //current speed
+ setText(*m_staticTextSpeed, perf->getBytesPerSecond(), &layoutChanged);
- if (statistics.get())
- {
- if (timeElapsed.Time() - lastStatCallSpeed >= 500) //call method every 500 ms
- {
- lastStatCallSpeed = timeElapsed.Time();
+ if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //update GUI every 2 sec
+ {
+ lastStatCallRemTime = timeElapsed.Time();
- statistics->addMeasurement(currentObjects, to<double>(currentData));
+ //remaining time
+ setText(*m_staticTextRemTime, perf->getRemainingTime(to<double>(dataTotal - dataCurrent)), &layoutChanged);
+ }
+ }
+ }
+ break;
- //current speed
- setText(*m_staticTextSpeed, statistics->getBytesPerSecond(), &layoutChanged);
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ assert(false);
+ break;
+ }
- if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //call method every two seconds only
- {
- lastStatCallRemTime = timeElapsed.Time();
+ //nr of scanned objects
+ setText(*m_staticTextScanned, scannedObjects, &layoutChanged);
- //remaining time
- setText(*m_staticTextRemTime, statistics->getRemainingTime(), &layoutChanged);
- }
- }
- }
+ //time elapsed
+ const long timeElapSec = timeElapsed.Time() / 1000;
+ setText(*m_staticTextTimeElapsed,
+ timeElapSec < 3600 ?
+ wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
+ wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged);
- //time elapsed
- const long timeElapSec = timeElapsed.Time() / 1000;
- setText(*m_staticTextTimeElapsed,
- timeElapSec < 3600 ?
- wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
- wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged);
+ //do the ui update
+ if (layoutChanged)
+ bSizer42->Layout();
- //do the ui update
- if (layoutChanged)
- bSizer42->Layout();
- }
updateUiNow();
}
//########################################################################################
//redirect to implementation
CompareStatus::CompareStatus(wxTopLevelWindow& parentWindow) :
- pimpl(new CompareStatusImpl(parentWindow)) {}
-
-CompareStatus::~CompareStatus()
-{
- //DON'T delete pimpl! it relies on wxWidgets destruction (parent window destroys child windows!)
-}
+ pimpl(new CompareStatusImpl(parentWindow)) {} //owned by parentWindow
wxWindow* CompareStatus::getAsWindow()
{
return pimpl;
}
-void CompareStatus::init()
+void CompareStatus::init(const Statistics& syncStat)
{
- pimpl->init();
+ pimpl->init(syncStat);
}
void CompareStatus::finalize()
@@ -336,29 +253,9 @@ void CompareStatus::finalize()
pimpl->finalize();
}
-void CompareStatus::switchToCompareBytewise(int totalObjectsToProcess, zen::Int64 totalDataToProcess)
-{
- pimpl->switchToCompareBytewise(totalObjectsToProcess, totalDataToProcess);
-}
-
-void CompareStatus::incScannedObjects_NoUpdate(int number)
-{
- pimpl->incScannedObjects_NoUpdate(number);
-}
-
-void CompareStatus::incProcessedCmpData_NoUpdate(int objectsDelta, Int64 dataDelta)
+void CompareStatus::switchToCompareBytewise()
{
- pimpl->incProcessedCmpData_NoUpdate(objectsDelta, dataDelta);
-}
-
-void CompareStatus::incTotalCmpData_NoUpdate(int objectsDelta, Int64 dataDelta)
-{
- pimpl->incTotalCmpData_NoUpdate(objectsDelta, dataDelta);
-}
-
-void CompareStatus::setStatusText_NoUpdate(const wxString& text)
-{
- pimpl->setStatusText_NoUpdate(text);
+ pimpl->switchToCompareBytewise();
}
void CompareStatus::updateStatusPanelNow()
@@ -399,14 +296,9 @@ public:
const int warningCount = log_.getItemCount(TYPE_WARNING);
const int infoCount = log_.getItemCount(TYPE_INFO);
- m_bpButtonErrors->init(buttonPressed ("error"), wxString(_("Error")) + wxString::Format(wxT(" (%d)"), errorCount),
- buttonReleased("error"), wxString(_("Error")) + wxString::Format(wxT(" (%d)"), errorCount));
-
- m_bpButtonWarnings->init(buttonPressed ("warning"), wxString(_("Warning")) + wxString::Format(wxT(" (%d)"), warningCount),
- buttonReleased("warning"), wxString(_("Warning")) + wxString::Format(wxT(" (%d)"), warningCount));
-
- m_bpButtonInfo->init(buttonPressed ("info"), wxString(_("Info")) + wxString::Format(wxT(" (%d)"), infoCount),
- buttonReleased("info"), wxString(_("Info")) + wxString::Format(wxT(" (%d)"), infoCount));
+ m_bpButtonErrors ->init(buttonPressed ("error" ), buttonReleased("error" ), _("Error" ) + wxString::Format(L" (%d)", errorCount ));
+ m_bpButtonWarnings->init(buttonPressed ("warning"), buttonReleased("warning"), _("Warning") + wxString::Format(L" (%d)", warningCount));
+ m_bpButtonInfo ->init(buttonPressed ("info" ), buttonReleased("info" ), _("Info" ) + wxString::Format(L" (%d)", infoCount ));
m_bpButtonErrors ->setActive(true);
m_bpButtonWarnings->setActive(true);
@@ -421,6 +313,7 @@ public:
m_textCtrlInfo->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(LogControl::onKeyEvent), nullptr, this);
}
+private:
virtual void OnErrors(wxCommandEvent& event)
{
m_bpButtonErrors->toggle();
@@ -439,7 +332,6 @@ public:
updateLogText();
}
-private:
void onKeyEvent(wxKeyEvent& event)
{
const int keyCode = event.GetKeyCode();
@@ -478,7 +370,7 @@ private:
logText += L'\n';
}
- if (logText.empty()) //if no messages match selected view filter, show final status message at least
+ if (logText.empty()) //if no messages match selected view filter, at least show final status message
if (!entries.empty())
logText = copyStringTo<zxString>(formatMessage(entries.back()));
@@ -490,7 +382,6 @@ private:
const ErrorLog log_;
};
-
//########################################################################################
namespace
@@ -498,20 +389,19 @@ namespace
class GraphDataBytes : public GraphData
{
public:
- void addCurrentValue(double dataCurrent)
+ void addRecord(double dataCurrent, long timeMs)
{
- data.insert(data.end(), std::make_pair(timer.Time(), dataCurrent));
+ data.insert(data.end(), std::make_pair(timeMs, dataCurrent));
//documentation differs about whether "hint" should be before or after the to be inserted element!
//however "std::map<>::end()" is interpreted correctly by GCC and VS2010
- if (data.size() > MAX_BUFFER_SIZE) //guard against too large a buffer
+ if (data.size() > MAX_BUFFER_SIZE) //limit buffer size
data.erase(data.begin());
}
- void pauseTimer () { timer.Pause(); }
- void resumeTimer() { timer.Resume(); }
+ void clear() { data.clear(); }
- virtual double getXBegin() const { return 0; } //{ return data.empty() ? 0 : data.begin()->first / 1000.0; }
+ virtual double getXBegin() const { return data.empty() ? 0 : data.begin()->first / 1000.0; } //need not start with 0, e.g. "binary comparison, graph reset, followed by sync"
virtual double getXEnd () const { return data.empty() ? 0 : (--data.end())->first / 1000.0; }
private:
@@ -526,7 +416,6 @@ private:
}
//example: two-element range is accessible within [0, 2)
- wxStopWatch timer;
std::map<long, double> data;
};
@@ -560,11 +449,7 @@ struct LabelFormatterBytes : public LabelFormatter
bytesProposed *= 1.5; //enlarge block default size
- //if (bytesProposed <= 1024 * 1024) //set 1 MB min size: reduce initial rapid changes in y-label
- // return 1024 * 1024;
-
//round to next number which is a convenient to read block size
-
const double k = std::floor(std::log(bytesProposed) / std::log(2.0));
const double e = std::pow(2.0, k);
if (numeric::isNull(e))
@@ -644,132 +529,125 @@ class SyncStatus::SyncStatusImpl : public SyncStatusDlgGenerated
{
public:
SyncStatusImpl(AbortCallback& abortCb,
+ const Statistics& syncStat,
MainDialog* parentWindow,
- SyncStatusID startStatus,
const wxString& jobName,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory);
~SyncStatusImpl();
- void initNewProcess(SyncStatusID id, int totalObjectsToProcess, Int64 totalDataToProcess);
-
- void incScannedObjects_NoUpdate(int number);
- void incProcessedData_NoUpdate(int objectsDelta, Int64 dataDelta);
- void incTotalData_NoUpdate (int objectsDelta, Int64 dataDelta);
-
- void setStatusText_NoUpdate(const wxString& text);
- void updateStatusDialogNow(bool allowYield = true);
+ void initNewPhase();
+ void reportCurrentBytes(Int64 currentData);
+ void updateProgress(bool allowYield = true);
- void processHasFinished(SyncStatus::SyncStatusID id, const ErrorLog& log); //essential to call this in StatusUpdater derived class destructor at the LATEST(!) to prevent access to currentStatusUpdater
+ //call this in StatusUpdater derived class destructor at the LATEST(!) to prevent access to currentStatusUpdater
+ void processHasFinished(SyncResult resultId, const ErrorLog& log);
+ void closeWindowDirectly();
std::wstring getExecWhenFinishedCommand() const;
- void stopTimer(); //halt all internal counters!
- void resumeTimer(); //
+ void stopTimer() //halt all internal counters!
+ {
+ m_animationControl1->Stop();
+ timeElapsed.Pause ();
+ }
+ void resumeTimer()
+ {
+ m_animationControl1->Play();
+ timeElapsed.Resume();
+ }
void minimizeToTray();
private:
void OnKeyPressed(wxKeyEvent& event);
- virtual void OnOkay(wxCommandEvent& event);
- virtual void OnPause(wxCommandEvent& event);
- virtual void OnAbort(wxCommandEvent& event);
- virtual void OnClose(wxCloseEvent& event);
+ virtual void OnOkay (wxCommandEvent& event);
+ virtual void OnPause (wxCommandEvent& event);
+ virtual void OnAbort (wxCommandEvent& event);
+ virtual void OnClose (wxCloseEvent& event);
virtual void OnIconize(wxIconizeEvent& event);
- void setCurrentStatus(SyncStatus::SyncStatusID id);
+ void updateDialogStatus();
void resumeFromSystray();
void OnResumeFromTray(wxCommandEvent& event);
- bool currentProcessIsRunning();
- void showProgressExternally(const wxString& progressText, double fraction = 0); //between [0, 1]
+ void setExternalStatus(const wxString& status, const wxString& progress); //progress may be empty!
const wxString jobName_;
wxStopWatch timeElapsed;
- AbortCallback* abortCb_; //temporarily bound
MainDialog* mainDialog; //optional
- //gauge variables
- int totalObjects; //file/dir/symlink/operation count
- Int64 totalData; //unit: [bytes]
- int currentObjects;
- Int64 currentData;
-
//status variables
- size_t scannedObjects;
- wxString currentStatusText;
+ AbortCallback* abortCb_; //temporarily bound while sync is running
+ const Statistics* syncStat_; //
+ bool paused_; //valid only while sync is running
+ SyncResult finalResult; //set after sync
- SyncStatus::SyncStatusID currentStatus;
- SyncStatus::SyncStatusID previousStatus; //save old status if "currentStatus == SyncStatus::PAUSED"
-
- std::unique_ptr<Taskbar> taskbar_;
+ bool isZombie; //wxGTK sends iconize event *after* wxWindow::Destroy, sigh...
//remaining time
- std::unique_ptr<Statistics> statistics;
- long lastStatCallSpeed; //used for calculating intervals between statistics update
+ std::unique_ptr<PerfCheck> perf;
+ long lastStatCallSpeed; //used for calculating intervals between collecting perf samples
long lastStatCallRemTime; //
std::shared_ptr<GraphDataBytes> graphDataBytes;
- //std::shared_ptr<GraphDataConstLine> graphDataBytesCurrent;
std::shared_ptr<GraphDataConstLine> graphDataBytesTotal;
wxString titelTextBackup;
-
std::unique_ptr<FfsTrayIcon> trayIcon; //optional: if filled all other windows should be hidden and conversely
+ std::unique_ptr<Taskbar> taskbar_;
};
SyncStatus::SyncStatusImpl::SyncStatusImpl(AbortCallback& abortCb,
+ const Statistics& syncStat,
MainDialog* parentWindow,
- SyncStatusID startStatus,
const wxString& jobName,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory) :
SyncStatusDlgGenerated(parentWindow,
wxID_ANY,
- parentWindow ? wxString(wxEmptyString) : (wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")),
+ parentWindow ? wxString() : (wxString(L"FreeFileSync - ") + _("Folder Comparison and Synchronization")),
wxDefaultPosition, wxSize(640, 350),
parentWindow ?
wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT : //wxTAB_TRAVERSAL is needed for standard button handling: wxID_OK/wxID_CANCEL
wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL),
- jobName_(jobName),
- abortCb_(&abortCb),
+ jobName_ (jobName),
mainDialog(parentWindow),
- totalObjects(0),
- totalData(0),
- currentObjects(0),
- currentData(0),
- scannedObjects(0),
- currentStatus (SyncStatus::ABORTED),
- previousStatus(SyncStatus::ABORTED),
- lastStatCallSpeed(-1000000), //some big number
+ abortCb_ (&abortCb),
+ syncStat_ (&syncStat),
+ paused_ (false),
+ finalResult(RESULT_ABORTED), //dummy value
+ isZombie(false),
+ lastStatCallSpeed (-1000000), //some big number
lastStatCallRemTime(-1000000)
{
#ifdef FFS_WIN
- new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
+ new MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
#endif
- if (mainDialog) //save old title (will be used as progress indicator)
- titelTextBackup = mainDialog->GetTitle();
+ if (mainDialog)
+ {
+ titelTextBackup = mainDialog->GetTitle(); //save old title (will be used as progress indicator)
+ mainDialog->disableAllElements(false); //disable all child elements
+ }
m_animationControl1->SetAnimation(GlobalResources::instance().animationSync);
m_animationControl1->Play();
+ SetIcon(GlobalResources::instance().programIcon);
+
//initialize gauge
m_gauge1->SetRange(GAUGE_FULL_RANGE);
m_gauge1->SetValue(0);
-
EnableCloseButton(false);
if (IsShown()) //don't steal focus when starting in sys-tray!
m_buttonAbort->SetFocus();
- if (mainDialog)
- mainDialog->disableAllElements(false); //disable all child elements
-
timeElapsed.Start(); //measure total time
try //try to get access to Windows 7/Ubuntu taskbar
@@ -780,39 +658,29 @@ SyncStatus::SyncStatusImpl::SyncStatusImpl(AbortCallback& abortCb,
//hide "processed" statistics until end of process
bSizerFinalStat ->Show(false);
- m_buttonOK ->Show(false);
m_staticTextLabelItemsProc->Show(false);
bSizerItemsProc ->Show(false);
-
- SetIcon(GlobalResources::instance().programIcon); //set application icon
+ m_buttonOK ->Show(false);
//register key event
Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(SyncStatusImpl::OnKeyPressed), nullptr, this);
- setCurrentStatus(startStatus); //first state: will be shown while waiting for dir locks (if at all)
-
//init graph
- graphDataBytes = std::make_shared<GraphDataBytes>();
- //graphDataBytesCurrent = std::make_shared<GraphDataConstLine>();
- graphDataBytesTotal = std::make_shared<GraphDataConstLine>();
+ graphDataBytes = std::make_shared<GraphDataBytes>();
+ graphDataBytesTotal = std::make_shared<GraphDataConstLine>();
m_panelGraph->setAttributes(Graph2D::GraphAttributes().
setLabelX(Graph2D::X_LABEL_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()).
setLabelY(Graph2D::Y_LABEL_RIGHT, 60, std::make_shared<LabelFormatterBytes>()));
- m_panelGraph->setData(graphDataBytesTotal, Graph2D::LineAttributes().setLineWidth(2).setColor(wxColor(0, 64, 0))); //green
- //m_panelGraph->addData(graphDataBytesCurrent, Graph2D::LineAttributes().setLineWidth(2).setColor(wxColor(0, 128, 0))); //green
- m_panelGraph->addData(graphDataBytes, Graph2D::LineAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0))); //medium green
+ m_panelGraph->setData(graphDataBytesTotal, Graph2D::LineAttributes().setLineWidth(2).setColor(wxColor(0, 64, 0))); //green
+ m_panelGraph->addData(graphDataBytes, Graph2D::LineAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0))); //medium green
//allow changing on completion command
- m_comboBoxExecFinished->setValue(execWhenFinished);
+ m_comboBoxExecFinished->setValue (execWhenFinished);
m_comboBoxExecFinished->setHistoryRef(execFinishedHistory);
- //Fit() height only:
- //fitHeight(*this);
-
- m_staticTextSpeed ->SetLabel(L""); //clear "dummy" values
- m_staticTextRemTime->SetLabel(L""); //
+ updateDialogStatus(); //null-status will be shown while waiting for dir locks (if at all)
}
@@ -838,12 +706,14 @@ void SyncStatus::SyncStatusImpl::OnKeyPressed(wxKeyEvent& event)
//simulate click on abort button
if (m_buttonAbort->IsShown()) //delegate to "abort" button if available
{
- m_buttonAbort->GetEventHandler()->ProcessEvent(dummy);
+ if (wxEvtHandler* handler = m_buttonAbort->GetEventHandler())
+ handler->ProcessEvent(dummy);
return;
}
- else if (m_buttonOK->IsShown()) //delegate to "abort" button if available
+ else if (m_buttonOK->IsShown())
{
- m_buttonOK->GetEventHandler()->ProcessEvent(dummy);
+ if (wxEvtHandler* handler = m_buttonOK->GetEventHandler())
+ handler->ProcessEvent(dummy);
return;
}
}
@@ -852,119 +722,37 @@ void SyncStatus::SyncStatusImpl::OnKeyPressed(wxKeyEvent& event)
}
-void SyncStatus::SyncStatusImpl::initNewProcess(SyncStatusID id, int totalObjectsToProcess, Int64 totalDataToProcess)
+void SyncStatus::SyncStatusImpl::initNewPhase()
{
- setCurrentStatus(id);
+ updateDialogStatus(); //evaluates "syncStat_->currentPhase()"
- currentData = 0;
- currentObjects = 0;
- totalData = totalDataToProcess;
- totalObjects = totalObjectsToProcess;
-
- incProcessedData_NoUpdate(0, 0); //update graph
- incTotalData_NoUpdate (0, 0); //
-
- //set new statistics handler: 10 seconds "window" for remaining time, 5 seconds for speed
- statistics.reset(new Statistics(totalObjectsToProcess, to<double>(totalDataToProcess), windowSizeRemainingTime, windowSizeBytesPerSec));
+ //reset graph (e.g. after binary comparison)
+ graphDataBytes->clear();
+ reportCurrentBytes(0);
+ //start new measurement
+ perf.reset(new PerfCheck(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC));
lastStatCallSpeed = -1000000; //some big number
lastStatCallRemTime = -1000000;
//set to 0 even if totalDataToProcess is 0: due to a bug in wxGauge::SetValue, it doesn't change to determinate mode when setting the old value again
- //so give updateStatusDialogNow() a chance to set a different value
+ //so give updateProgress() a chance to set a different value
m_gauge1->SetValue(0);
- updateStatusDialogNow(false); //get rid of "dummy" texts!
-}
-
-
-void SyncStatus::SyncStatusImpl::incProcessedData_NoUpdate(int objectsDelta, Int64 dataDelta)
-{
- currentData += dataDelta;
- currentObjects += objectsDelta;
-
- //update graph data
- graphDataBytes->addCurrentValue(to<double>(currentData));
+ updateProgress(false);
}
-void SyncStatus::SyncStatusImpl::incTotalData_NoUpdate(int objectsDelta, Int64 dataDelta)
+void SyncStatus::SyncStatusImpl::reportCurrentBytes(Int64 currentData)
{
- totalData += dataDelta;
- totalObjects += objectsDelta;
-
- if (statistics)
- statistics->setNewTotal(totalObjects, to<double>(totalData));
-
- graphDataBytesTotal->setValue(to<double>(totalData));
- //m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMaxY(to<double>(totalDataToProcess)));
+ //add sample for perf measurements + calc. of remaining time
+ graphDataBytes->addRecord(to<double>(currentData), timeElapsed.Time());
}
-void SyncStatus::SyncStatusImpl::incScannedObjects_NoUpdate(int number)
-{
- scannedObjects += number;
-}
-
-
-void SyncStatus::SyncStatusImpl::setStatusText_NoUpdate(const wxString& text)
-{
- currentStatusText = text;
-}
-
-
-void SyncStatus::SyncStatusImpl::showProgressExternally(const wxString& progressText, double fraction)
-{
- //write status information to systray, if window is minimized
- if (trayIcon.get())
- trayIcon->setToolTip(progressText, fraction);
-
- wxString progressTextFmt = progressText;
- progressTextFmt.Replace(wxT("\n"), wxT(" - "));
-
- if (mainDialog) //show percentage in maindialog title (and thereby in taskbar)
- {
- if (mainDialog->GetTitle() != progressTextFmt)
- mainDialog->SetTitle(progressTextFmt);
- }
- else //show percentage in this dialog's title (and thereby in taskbar)
- {
- if (this->GetTitle() != progressTextFmt)
- this->SetTitle(progressTextFmt);
- }
-
-
- //show progress on Windows 7 taskbar
- if (taskbar_.get())
- {
- switch (currentStatus)
- {
- case SyncStatus::SCANNING:
- taskbar_->setStatus(Taskbar::STATUS_INDETERMINATE);
- break;
- case SyncStatus::FINISHED_WITH_SUCCESS:
- case SyncStatus::COMPARING_CONTENT:
- case SyncStatus::SYNCHRONIZING:
- taskbar_->setProgress(fraction);
- taskbar_->setStatus(Taskbar::STATUS_NORMAL);
- break;
- case SyncStatus::PAUSE:
- taskbar_->setProgress(fraction);
- taskbar_->setStatus(Taskbar::STATUS_PAUSED);
- break;
- case SyncStatus::ABORTED:
- case SyncStatus::FINISHED_WITH_ERROR:
- taskbar_->setProgress(fraction);
- taskbar_->setStatus(Taskbar::STATUS_ERROR);
- break;
- }
- }
-}
-
-
-#ifdef FFS_WIN
namespace
{
+#ifdef FFS_WIN
enum Zorder
{
ZORDER_CORRECT,
@@ -988,131 +776,183 @@ Zorder evaluateZorder(const wxWindow& top, const wxWindow& bottom)
return ZORDER_INDEFINITE;
}
-}
#endif
-void SyncStatus::SyncStatusImpl::updateStatusDialogNow(bool allowYield)
+std::wstring getDialogStatusText(const Statistics* syncStat, bool paused, SyncStatus::SyncResult finalResult)
+{
+ if (syncStat) //sync running
+ {
+ if (paused)
+ return _("Paused");
+ else
+ switch (syncStat->currentPhase())
+ {
+ case ProcessCallback::PHASE_NONE:
+ return _("Initializing..."); //dialog is shown *before* sync starts, so this text may be visible!
+ case ProcessCallback::PHASE_SCANNING:
+ return _("Scanning...");
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ return _("Comparing content...");
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ return _("Synchronizing...");
+ }
+ }
+ else //sync finished
+ switch (finalResult)
+ {
+ case SyncStatus::RESULT_ABORTED:
+ return _("Aborted");
+ case SyncStatus::RESULT_FINISHED_WITH_ERROR:
+ case SyncStatus::RESULT_FINISHED_WITH_SUCCESS:
+ return _("Completed");
+ }
+ return std::wstring();
+}
+}
+
+
+void SyncStatus::SyncStatusImpl::setExternalStatus(const wxString& status, const wxString& progress) //progress may be empty!
{
- //static RetrieveStatistics statistic;
- //statistic.writeEntry(currentData.ToDouble(), currentObjects);
+ //sys tray: order "top-down": jobname, status, progress
+ wxString newTrayInfo = jobName_.empty() ? status : L"\"" + jobName_ + L"\"\n" + status;
+ if (!progress.empty())
+ newTrayInfo += L" " + progress;
- //add both data + obj-count, to handle "deletion-only" cases
- const double fraction = totalData + totalObjects == 0 ? 1 : std::max(0.0, to<double>(currentData + currentObjects) / to<double>(totalData + totalObjects));
- //yes, this may legitimately become < 0: failed rename operation falls-back to copy + delete, reducing "currentData" to potentially < 0!
+ //window caption/taskbar; inverse order: progress, status, jobname
+ wxString newCaption = progress.empty() ? status : progress + L" - " + status;
+ if (!jobName_.empty())
+ newCaption += L" - \"" + jobName_ + L"\"";
- //write status information to systray, taskbar, parent title ect.
+ //systray tooltip, if window is minimized
+ if (trayIcon.get())
+ trayIcon->setToolTip(newTrayInfo);
- const wxString postFix = jobName_.empty() ? wxString() : (wxT("\n\"") + jobName_ + wxT("\""));
- switch (currentStatus)
+ //show text in dialog title (and at the same time in taskbar)
+ if (mainDialog)
{
- case SyncStatus::SCANNING:
- showProgressExternally(wxString() + toStringSep(scannedObjects) + wxT(" - ") + _("Scanning...") + postFix);
- break;
- case SyncStatus::COMPARING_CONTENT:
- showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Comparing content...") + postFix, fraction);
- break;
- case SyncStatus::SYNCHRONIZING:
- showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Synchronizing...") + postFix, fraction);
- break;
- case SyncStatus::PAUSE:
- showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Paused") + postFix, fraction);
- break;
- case SyncStatus::ABORTED:
- showProgressExternally(_("Aborted") + postFix, fraction);
- break;
- case SyncStatus::FINISHED_WITH_SUCCESS:
- case SyncStatus::FINISHED_WITH_ERROR:
- showProgressExternally(_("Completed") + postFix, fraction);
- break;
+ if (mainDialog->GetTitle() != newCaption)
+ mainDialog->SetTitle(newCaption);
}
-
- //write regular status information (whether dialog is visible or not)
+ else
{
- //wxWindowUpdateLocker dummy(this); -> not needed
+ if (this->GetTitle() != newCaption)
+ this->SetTitle(newCaption);
+ }
+}
- bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
- //progress indicator
- switch (currentStatus)
- {
- case SyncStatus::SCANNING:
- m_gauge1->Pulse();
- break;
- case SyncStatus::COMPARING_CONTENT:
- case SyncStatus::SYNCHRONIZING:
- case SyncStatus::FINISHED_WITH_SUCCESS:
- case SyncStatus::FINISHED_WITH_ERROR:
- case SyncStatus::ABORTED:
- m_gauge1->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE));
- break;
- case SyncStatus::PAUSE: //no change to gauge: don't switch between indeterminate/determinate modus
- break;
- }
+void SyncStatus::SyncStatusImpl::updateProgress(bool allowYield)
+{
+ assert(syncStat_);
+ if (!syncStat_) //no sync running!!
+ return;
+ //wxWindowUpdateLocker dummy(this); -> not needed
- wxString statusTextFmt = currentStatusText; //remove linebreaks
- replace(statusTextFmt, L'\n', L' '); //
+ bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
- //status text
- if (m_textCtrlInfo->GetValue() != statusTextFmt) //no layout update for status texts!
- m_textCtrlInfo->ChangeValue(statusTextFmt);
+ //sync status text
+ setText(*m_textCtrlInfo, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts!
- //remaining objects
- const wxString remainingObjTmp = toStringSep(totalObjects - currentObjects);
- setText(*m_staticTextRemainingObj, remainingObjTmp, &layoutChanged);
+ switch (syncStat_->currentPhase()) //no matter if paused or not
+ {
+ case ProcessCallback::PHASE_NONE:
+ case ProcessCallback::PHASE_SCANNING:
+ //dialog caption, taskbar, systray tooltip
+ setExternalStatus(getDialogStatusText(syncStat_, paused_, finalResult), toStringSep(syncStat_->getObjectsCurrent(ProcessCallback::PHASE_SCANNING))); //status text may be "paused"!
- //remaining bytes left for copy
- const wxString remainingBytesTmp = zen::filesizeToShortString(totalData - currentData);
- setText(*m_staticTextDataRemaining, remainingBytesTmp, &layoutChanged);
+ //progress indicators
+ m_gauge1->Pulse();
+ if (trayIcon.get()) trayIcon->setProgress(1); //1 = regular FFS logo
- //statistics
- if (statistics.get())
- {
- if (timeElapsed.Time() - lastStatCallSpeed >= 500) //call method every 500 ms
- {
- lastStatCallSpeed = timeElapsed.Time();
+ //taskbar_ status is Taskbar::STATUS_INDETERMINATE
+
+ //constant line graph
+ graphDataBytesTotal->setValue(0);
- statistics->addMeasurement(currentObjects, to<double>(currentData));
+ //remaining objects and data
+ setText(*m_staticTextRemainingObj , L"-", &layoutChanged);
+ setText(*m_staticTextDataRemaining, L"", &layoutChanged);
- //current speed
- setText(*m_staticTextSpeed, statistics->getBytesPerSecond(), &layoutChanged);
+ //remaining time and speed
+ setText(*m_staticTextSpeed, L"-", &layoutChanged);
+ setText(*m_staticTextRemTime, L"-", &layoutChanged);
+ break;
- if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //call method every two seconds only
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ {
+ auto objectsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase());
+ auto objectsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase());
+ auto dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase());
+ auto dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase());
+
+ //add both data + obj-count, to handle "deletion-only" cases
+ const double fraction = dataTotal + objectsTotal == 0 ? 1 : std::max(0.0, to<double>(dataCurrent + objectsCurrent) / to<double>(dataTotal + objectsTotal));
+ //yes, this may legitimately become < 0: failed rename operation falls-back to copy + delete, reducing "dataCurrent" to potentially < 0!
+ //----------------------------------------------------------------------------------------------------
+
+ //dialog caption, taskbar, systray tooltip
+ setExternalStatus(getDialogStatusText(syncStat_, paused_, finalResult), fractionToShortString(fraction)); //status text may be "paused"!
+
+ //progress indicators
+ m_gauge1->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE));
+ if (trayIcon.get()) trayIcon->setProgress(fraction);
+ if (taskbar_.get()) taskbar_->setProgress(fraction);
+
+ //constant line graph
+ graphDataBytesTotal->setValue(to<double>(dataTotal));
+
+ //remaining objects and data
+ setText(*m_staticTextRemainingObj, toStringSep(objectsTotal - objectsCurrent), &layoutChanged);
+ setText(*m_staticTextDataRemaining, L"(" + filesizeToShortString(dataTotal - dataCurrent) + L")", &layoutChanged);
+
+ //remaining time and speed
+ assert(perf);
+ if (perf)
+ if (timeElapsed.Time() - lastStatCallSpeed >= 500) //-> Win 7 copy uses 1 sec update interval
{
- lastStatCallRemTime = timeElapsed.Time();
+ lastStatCallSpeed = timeElapsed.Time();
- //remaining time
- setText(*m_staticTextRemTime, statistics->getRemainingTime(), &layoutChanged);
- }
- }
- }
+ perf->addSample(objectsCurrent, to<double>(dataCurrent), timeElapsed.Time());
- {
- m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMinX(graphDataBytes->getXBegin()));
- m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMaxX(graphDataBytes->getXEnd()));
+ //current speed
+ setText(*m_staticTextSpeed, perf->getBytesPerSecond(), &layoutChanged);
- m_panelGraph->Refresh();
+ if (timeElapsed.Time() - lastStatCallRemTime >= 2000) //update GUI every 2 sec
+ {
+ lastStatCallRemTime = timeElapsed.Time();
+
+ //remaining time
+ setText(*m_staticTextRemTime, perf->getRemainingTime(to<double>(dataTotal - dataCurrent)), &layoutChanged);
+ }
+ }
}
+ break;
+ }
- //time elapsed
- const long timeElapSec = timeElapsed.Time() / 1000;
- setText(*m_staticTextTimeElapsed,
- timeElapSec < 3600 ?
- wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
- wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged);
+ m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMinX(graphDataBytes->getXBegin()));
+ m_panelGraph->setAttributes(m_panelGraph->getAttributes().setMaxX(graphDataBytes->getXEnd()));
+ m_panelGraph->Refresh();
- //do the ui update
- if (layoutChanged)
- {
- // Layout();
- // bSizerItemsRem->Layout();
- // bSizer171->Layout();
- bSizerProgressStat->Layout(); //
- m_panelProgress->Layout(); //both needed
- //m_panelBackground->Layout(); //we use a dummy panel as actual background: replaces simple "Layout()" call
- //-> it seems this layout is not required, and even harmful: resets m_comboBoxExecFinished dropdown while user is selecting!
- }
+ //time elapsed
+ const long timeElapSec = timeElapsed.Time() / 1000;
+ setText(*m_staticTextTimeElapsed,
+ timeElapSec < 3600 ?
+ wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
+ wxTimeSpan::Seconds(timeElapSec).Format(L"%H:%M:%S"), &layoutChanged);
+
+ //do the ui update
+ if (layoutChanged)
+ {
+ // Layout();
+ // bSizerItemsRem->Layout();
+ // bSizer171->Layout();
+ bSizerProgressStat->Layout(); //
+ m_panelProgress->Layout(); //both needed
+ //m_panelBackground->Layout(); //we use a dummy panel as actual background: replaces simple "Layout()" call
+ //-> it seems this layout is not required, and even harmful: resets m_comboBoxExecFinished dropdown while user is selecting!
}
#ifdef FFS_WIN
@@ -1132,92 +972,195 @@ void SyncStatus::SyncStatusImpl::updateStatusDialogNow(bool allowYield)
if (allowYield)
{
//support for pause button
- while (currentStatus == SyncStatus::PAUSE && currentProcessIsRunning())
+ if (paused_)
{
- wxMilliSleep(UI_UPDATE_INTERVAL);
- updateUiNow();
+ stopTimer();
+ while (paused_)
+ {
+ wxMilliSleep(UI_UPDATE_INTERVAL);
+ updateUiNow(); //receive UI message that ends pause
+ }
+ resumeTimer();
}
-
/*
/|\
- | keep this order to ensure one full statistics update before entering pause mode
+ | keep this sequence to ensure one full progress update before entering pause mode!
\|/
*/
- updateUiNow();
+ updateUiNow(); //receive UI message that sets pause status
}
else
Update(); //don't wait until next idle event (who knows what blocking process comes next?)
}
-bool SyncStatus::SyncStatusImpl::currentProcessIsRunning()
-{
- return abortCb_ != nullptr;
-}
-
-
std::wstring SyncStatus::SyncStatusImpl::getExecWhenFinishedCommand() const
{
return m_comboBoxExecFinished->getValue();
}
-void SyncStatus::SyncStatusImpl::setCurrentStatus(SyncStatus::SyncStatusID id)
+void SyncStatus::SyncStatusImpl::updateDialogStatus() //depends on "syncStat_, paused_, finalResult"
{
- switch (id)
+ m_staticTextStatus->SetLabel(getDialogStatusText(syncStat_, paused_, finalResult));
+
+ if (syncStat_) //sync running
{
- case SyncStatus::ABORTED:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusError")));
- m_staticTextStatus->SetLabel(_("Aborted"));
- break;
+ if (paused_)
+ m_buttonPause->SetLabel(_("Continue"));
+ else
+ m_buttonPause->SetLabel(_("Pause"));
+
+ if (paused_)
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusPause"));
+ else
+ switch (syncStat_->currentPhase())
+ {
+ case ProcessCallback::PHASE_NONE:
+ break;
- case SyncStatus::FINISHED_WITH_SUCCESS:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusSuccess")));
- m_staticTextStatus->SetLabel(_("Completed"));
- break;
+ case ProcessCallback::PHASE_SCANNING:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusScanning"));
+ break;
- case SyncStatus::FINISHED_WITH_ERROR:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusWarning")));
- m_staticTextStatus->SetLabel(_("Completed"));
- break;
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusBinaryCompare"));
+ break;
- case SyncStatus::PAUSE:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusPause")));
- m_staticTextStatus->SetLabel(_("Paused"));
- break;
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusSyncing"));
+ break;
+ }
+ }
+ else //sync finished
+ switch (finalResult)
+ {
+ case RESULT_ABORTED:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusError"));
+ break;
- case SyncStatus::SCANNING:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusScanning")));
- m_staticTextStatus->SetLabel(_("Scanning..."));
- break;
+ case RESULT_FINISHED_WITH_ERROR:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusWarning"));
+ break;
- case SyncStatus::COMPARING_CONTENT:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusBinaryCompare")));
- m_staticTextStatus->SetLabel(_("Comparing content..."));
- break;
+ case RESULT_FINISHED_WITH_SUCCESS:
+ m_bitmapStatus->SetBitmap(GlobalResources::getImage(L"statusSuccess"));
+ break;
+ }
- case SyncStatus::SYNCHRONIZING:
- m_bitmapStatus->SetBitmap(GlobalResources::getImage(wxT("statusSyncing")));
- m_staticTextStatus->SetLabel(_("Synchronizing..."));
- break;
+ //show status on Windows 7 taskbar
+ if (taskbar_.get())
+ {
+ if (syncStat_) //sync running
+ {
+ if (paused_)
+ taskbar_->setStatus(Taskbar::STATUS_PAUSED);
+ else
+ switch (syncStat_->currentPhase())
+ {
+ case ProcessCallback::PHASE_NONE:
+ case ProcessCallback::PHASE_SCANNING:
+ taskbar_->setStatus(Taskbar::STATUS_INDETERMINATE);
+ break;
+
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ taskbar_->setStatus(Taskbar::STATUS_NORMAL);
+ break;
+ }
+ }
+ else //sync finished
+ switch (finalResult)
+ {
+ case RESULT_ABORTED:
+ case RESULT_FINISHED_WITH_ERROR:
+ taskbar_->setStatus(Taskbar::STATUS_ERROR);
+ break;
+
+ case RESULT_FINISHED_WITH_SUCCESS:
+ taskbar_->setStatus(Taskbar::STATUS_NORMAL);
+ break;
+ }
}
- currentStatus = id;
-
m_panelBackground->Layout(); //we use a dummy panel as actual background: replaces simple "Layout()" call
}
-void SyncStatus::SyncStatusImpl::processHasFinished(SyncStatus::SyncStatusID id, const ErrorLog& log) //essential to call this in StatusHandler derived class destructor
+void SyncStatus::SyncStatusImpl::closeWindowDirectly() //this should really be called: do not call back + schedule deletion
+{
+ paused_ = false; //you never know?
+
+ //ATTENTION: dialog may live a little longer, so cut callbacks!
+ //e.g. wxGTK calls OnIconize after wxWindow::Close() (better not ask why) and before physical destruction! => indirectly calls updateDialogStatus(), which reads syncStat_!!!
+
+ //------- change class state -------
+ abortCb_ = nullptr; //avoid callback to (maybe) deleted parent process
+ syncStat_ = nullptr; //set *after* last call to "updateProgress"
+ //----------------------------------
+
+ Close();
+}
+
+
+void SyncStatus::SyncStatusImpl::processHasFinished(SyncResult resultId, const ErrorLog& log) //essential to call this in StatusHandler derived class destructor
{
//at the LATEST(!) to prevent access to currentStatusHandler
//enable okay and close events; may be set in this method ONLY
wxWindowUpdateLocker dummy(this); //badly needed
- abortCb_ = nullptr; //avoid callback to (maybe) deleted parent process
+ paused_ = false; //you never know?
- setCurrentStatus(id);
+ //update numbers one last time (as if sync were still running)
+ updateProgress(false);
+
+ switch (syncStat_->currentPhase()) //no matter if paused or not
+ {
+ case ProcessCallback::PHASE_NONE:
+ case ProcessCallback::PHASE_SCANNING:
+ //set overall speed -> not needed
+ //items processed -> not needed
+ break;
+
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ {
+ auto objectsCurrent = syncStat_->getObjectsCurrent(syncStat_->currentPhase());
+ auto objectsTotal = syncStat_->getObjectsTotal (syncStat_->currentPhase());
+ auto dataCurrent = syncStat_->getDataCurrent (syncStat_->currentPhase());
+ auto dataTotal = syncStat_->getDataTotal (syncStat_->currentPhase());
+
+ //set overall speed (instead of current speed)
+ assert(perf);
+ if (perf)
+ m_staticTextSpeed->SetLabel(perf->getOverallBytesPerSecond()); //note: we can't simply divide "sync total bytes" by "timeElapsed"
+
+ //show new element "items processed"
+ m_staticTextLabelItemsProc->Show(true);
+ bSizerItemsProc ->Show(true);
+ m_staticTextProcessedObj ->SetLabel(toStringSep(objectsCurrent));
+ m_staticTextDataProcessed->SetLabel(L"(" + filesizeToShortString(dataCurrent) + L")");
+
+ //hide remaining elements...
+ if (objectsCurrent == objectsTotal && //...if everything was processed successfully
+ dataCurrent == dataTotal)
+ {
+ m_staticTextLabelItemsRem->Show(false);
+ bSizerItemsRem ->Show(false);
+ }
+ }
+ break;
+ }
+
+ //------- change class state -------
+ abortCb_ = nullptr; //avoid callback to (maybe) deleted parent process
+ syncStat_ = nullptr; //set *after* last call to "updateProgress"
+ finalResult = resultId;
+ //----------------------------------
+
+ updateDialogStatus();
+ setExternalStatus(getDialogStatusText(syncStat_, paused_, finalResult), wxString());
resumeFromSystray(); //if in tray mode...
@@ -1244,45 +1187,30 @@ void SyncStatus::SyncStatusImpl::processHasFinished(SyncStatus::SyncStatusID id,
//show and prepare final statistics
bSizerFinalStat->Show(true);
- if (totalObjects == currentObjects && //if everything was processed successfully
- totalData == currentData)
- {
- m_staticTextLabelItemsRem->Show(false);
- bSizerItemsRem ->Show(false);
- }
-
- m_staticTextLabelItemsProc->Show(true);
- bSizerItemsProc ->Show(true);
- m_staticTextProcessedObj ->SetLabel(toStringSep(currentObjects));
- m_staticTextDataProcessed->SetLabel(zen::filesizeToShortString(currentData));
-
+ //show total time
m_staticTextLabelElapsedTime->SetLabel(_("Total time:")); //it's not "elapsed time" anymore
+ //hide remaining time
m_staticTextLabelRemTime->Show(false);
m_staticTextRemTime ->Show(false);
- updateStatusDialogNow(false); //keep this sequence to avoid display distortion, if e.g. only 1 item is sync'ed
-
- //changed meaning: from current to overall speed: -> make sure to call after "updateStatusDialogNow"
- const long timeElapMs = timeElapsed.Time();
- m_staticTextSpeed->SetLabel(timeElapMs <= 0 ? L"-" : zen::filesizeToShortString(currentData * 1000 / timeElapMs) + _("/sec"));
-
- //fill result listbox:
-
//workaround wxListBox bug on Windows XP: labels are drawn on top of each other
assert(m_listbookResult->GetImageList()); //make sure listbook keeps *any* image list
//due to some crazy reasons that aren't worth debugging, this needs to be done directly in wxFormBuilder,
- //the following call is *not* sufficient: m_listbookResult->AssignImageList(new wxImageList(0, 0));
+ //the following call is *not* sufficient: m_listbookResult->AssignImageList(new wxImageList(180, 1));
//note: alternative solutions involving wxLC_LIST, wxLC_REPORT and SetWindowStyleFlag() do not work portably! wxListBook using wxLC_ICON is obviously a class invariant!
//1. re-arrange graph into results listbook
bSizerTop->Detach(m_panelProgress);
m_panelProgress->Reparent(m_listbookResult);
+#ifdef FFS_LINUX
+ wxYield(); //wxGTK 2.9.3 fails miserably at "reparent" whithout this
+#endif
m_listbookResult->AddPage(m_panelProgress, _("Statistics"), true); //AddPage() takes ownership!
//2. log file
const size_t posLog = 1;
- LogControl* logControl = new LogControl(m_listbookResult, log);
+ LogControl* logControl = new LogControl(m_listbookResult, log); //owned by m_listbookResult
m_listbookResult->AddPage(logControl, _("Logging"), false);
//bSizerHoldStretch->Insert(0, logControl, 1, wxEXPAND);
@@ -1304,62 +1232,19 @@ void SyncStatus::SyncStatusImpl::OnOkay(wxCommandEvent& event)
void SyncStatus::SyncStatusImpl::OnAbort(wxCommandEvent& event)
{
- if (currentStatus == SyncStatus::PAUSE)
- {
- wxCommandEvent dummy;
- OnPause(dummy);
- }
-
- if (currentProcessIsRunning())
- {
- m_buttonAbort->Disable();
- m_buttonAbort->Hide();
- m_buttonPause->Disable();
- m_buttonPause->Hide();
-
- setStatusText_NoUpdate(_("Abort requested: Waiting for current operation to finish..."));
- //no Layout() or UI-update here to avoid cascaded Yield()-call
+ paused_ = false;
+ updateDialogStatus(); //update status + pause button
+ //no Layout() or UI-update here to avoid cascaded Yield()-call
+ if (abortCb_)
abortCb_->requestAbortion();
- }
-}
-
-
-void SyncStatus::SyncStatusImpl::stopTimer()
-{
- timeElapsed.Pause();
- if (statistics.get()) statistics->pauseTimer();
- graphDataBytes->pauseTimer();
-}
-
-
-void SyncStatus::SyncStatusImpl::resumeTimer()
-{
- timeElapsed.Resume();
- if (statistics.get()) statistics->resumeTimer();
- graphDataBytes->resumeTimer();
}
void SyncStatus::SyncStatusImpl::OnPause(wxCommandEvent& event)
{
- if (currentStatus == SyncStatus::PAUSE)
- {
- resumeTimer();
- setCurrentStatus(previousStatus);
-
- m_buttonPause->SetLabel(_("Pause"));
- m_animationControl1->Play();
- }
- else
- {
- stopTimer();
- previousStatus = currentStatus; //save current status
- setCurrentStatus(SyncStatus::PAUSE);
-
- m_buttonPause->SetLabel(_("Continue"));
- m_animationControl1->Stop();
- }
+ paused_ = !paused_;
+ updateDialogStatus(); //update status + pause button
}
@@ -1367,16 +1252,19 @@ void SyncStatus::SyncStatusImpl::OnClose(wxCloseEvent& event)
{
//this event handler may be called due to a system shutdown DURING synchronization!
//try to stop sync gracefully and cross fingers:
- if (currentProcessIsRunning())
+ if (abortCb_)
abortCb_->requestAbortion();
- //Note: we must NOT veto dialog destruction, else we will cancel system shutdown if this dialog is application main window (like in batch mode)
+ //Note: we must NOT veto dialog destruction, else we will cancel system shutdown if this dialog is application main window (as in batch mode)
+ isZombie = true; //it "lives" until cleanup in next idle event
Destroy();
}
void SyncStatus::SyncStatusImpl::OnIconize(wxIconizeEvent& event)
{
+ if (isZombie) return; //wxGTK sends iconize event *after* wxWindow::Destroy, sigh...
+
if (event.IsIconized()) //ATTENTION: iconize event is also triggered on "Restore"! (at least under Linux)
minimizeToTray();
else
@@ -1399,7 +1287,8 @@ void SyncStatus::SyncStatusImpl::minimizeToTray()
//tray icon has shorter lifetime than this => no need to disconnect event later
}
- updateStatusDialogNow(false); //set tooltip: e.g. in pause mode there was no GUI update, so this is the last chance
+ if (syncStat_)
+ updateProgress(false); //set tray tooltip + progress: e.g. no updates while paused
Hide();
if (mainDialog)
@@ -1425,7 +1314,9 @@ void SyncStatus::SyncStatusImpl::resumeFromSystray()
Raise();
SetFocus();
- updateStatusDialogNow(false); //restore Windows 7 task bar status (e.g. required in pause mode)
+ updateDialogStatus(); //restore Windows 7 task bar status (e.g. required in pause mode)
+ if (syncStat_)
+ updateProgress(false); //restore Windows 7 task bar progress (e.g. required in pause mode)
}
@@ -1434,18 +1325,18 @@ void SyncStatus::SyncStatusImpl::resumeFromSystray()
//redirect to implementation
SyncStatus::SyncStatus(AbortCallback& abortCb,
+ const Statistics& syncStat,
MainDialog* parentWindow,
- SyncStatusID startStatus,
bool showProgress,
const wxString& jobName,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory) :
- pimpl(new SyncStatusImpl(abortCb, parentWindow, startStatus, jobName, execWhenFinished, execFinishedHistory))
+ pimpl(new SyncStatusImpl(abortCb, syncStat, parentWindow, jobName, execWhenFinished, execFinishedHistory))
{
if (showProgress)
{
pimpl->Show();
- pimpl->updateStatusDialogNow(false); //clear gui flicker: window must be visible to make this work!
+ pimpl->updateProgress(false); //clear gui flicker, remove dummy texts: window must be visible to make this work!
}
else
pimpl->minimizeToTray();
@@ -1461,34 +1352,19 @@ wxWindow* SyncStatus::getAsWindow()
return pimpl;
}
-void SyncStatus::initNewProcess(SyncStatusID id, int totalObjectsToProcess, Int64 totalDataToProcess)
-{
- pimpl->initNewProcess(id, totalObjectsToProcess, totalDataToProcess);
-}
-
-void SyncStatus::incScannedObjects_NoUpdate(int number)
-{
- pimpl->incScannedObjects_NoUpdate(number);
-}
-
-void SyncStatus::incProcessedData_NoUpdate(int objectsDelta, Int64 dataDelta)
-{
- pimpl->incProcessedData_NoUpdate(objectsDelta, dataDelta);
-}
-
-void SyncStatus::incTotalData_NoUpdate(int objectsDelta, Int64 dataDelta)
+void SyncStatus::initNewPhase()
{
- pimpl->incTotalData_NoUpdate(objectsDelta, dataDelta);
+ pimpl->initNewPhase();
}
-void SyncStatus::setStatusText_NoUpdate(const wxString& text)
+void SyncStatus::reportCurrentBytes(Int64 currentData)
{
- pimpl->setStatusText_NoUpdate(text);
+ pimpl->reportCurrentBytes(currentData);
}
-void SyncStatus::updateStatusDialogNow()
+void SyncStatus::updateProgress()
{
- pimpl->updateStatusDialogNow();
+ pimpl->updateProgress();
}
std::wstring SyncStatus::getExecWhenFinishedCommand() const
@@ -1506,12 +1382,12 @@ void SyncStatus::resumeTimer()
return pimpl->resumeTimer();
}
-void SyncStatus::processHasFinished(SyncStatusID id, const ErrorLog& log)
+void SyncStatus::processHasFinished(SyncResult resultId, const ErrorLog& log)
{
- pimpl->processHasFinished(id, log);
+ pimpl->processHasFinished(resultId, log);
}
void SyncStatus::closeWindowDirectly() //don't wait for user (silent mode)
{
- pimpl->Destroy();
+ pimpl->closeWindowDirectly();
}
diff --git a/ui/progress_indicator.h b/ui/progress_indicator.h
index 858f6ce9..cd974408 100644
--- a/ui/progress_indicator.h
+++ b/ui/progress_indicator.h
@@ -18,18 +18,13 @@ class CompareStatus
{
public:
CompareStatus(wxTopLevelWindow& parentWindow); //CompareStatus will be owned by parentWindow!
- ~CompareStatus();
wxWindow* getAsWindow(); //convenience! don't abuse!
- void init(); //make visible, initialize all status values
- void finalize(); //hide again
+ void init(const zen::Statistics& syncStat); //begin of sync: make visible, set pointer to "syncStat", initialize all status values
+ void finalize(); //end of sync: hide again, clear pointer to "syncStat"
- void switchToCompareBytewise(int totalObjectsToProcess, zen::Int64 totalDataToProcess);
- void incScannedObjects_NoUpdate(int number);
- void incProcessedCmpData_NoUpdate(int objectsDelta, zen::Int64 dataDelta);
- void incTotalCmpData_NoUpdate (int objectsDelta, zen::Int64 dataDelta);
- void setStatusText_NoUpdate(const wxString& text);
+ void switchToCompareBytewise();
void updateStatusPanelNow();
private:
@@ -41,20 +36,9 @@ private:
class SyncStatus
{
public:
- enum SyncStatusID
- {
- ABORTED,
- FINISHED_WITH_SUCCESS,
- FINISHED_WITH_ERROR,
- PAUSE,
- SCANNING,
- COMPARING_CONTENT,
- SYNCHRONIZING
- };
-
- SyncStatus(AbortCallback& abortCb,
+ SyncStatus(zen::AbortCallback& abortCb,
+ const zen::Statistics& syncStat,
MainDialog* parentWindow, //may be nullptr
- SyncStatusID startStatus,
bool showProgress,
const wxString& jobName,
const std::wstring& execWhenFinished,
@@ -63,22 +47,25 @@ public:
wxWindow* getAsWindow(); //convenience! don't abuse!
- void initNewProcess(SyncStatusID id, int totalObjectsToProcess, zen::Int64 totalDataToProcess);
+ void initNewPhase(); //call after "StatusHandler::initNewPhase"
- void incScannedObjects_NoUpdate(int number);
- void incProcessedData_NoUpdate(int objectsDelta, zen::Int64 dataDelta);
- void incTotalData_NoUpdate (int objectsDelta, zen::Int64 dataDelta);
- void setStatusText_NoUpdate(const wxString& text);
- void updateStatusDialogNow();
+ void reportCurrentBytes(zen::Int64 currentData); //throw (), required by graph!
+ void updateProgress();
std::wstring getExecWhenFinishedCommand() const; //final value (after possible user modification)
void stopTimer(); //halt all internal counters!
void resumeTimer(); //
+ enum SyncResult
+ {
+ RESULT_ABORTED,
+ RESULT_FINISHED_WITH_ERROR,
+ RESULT_FINISHED_WITH_SUCCESS
+ };
//essential to call one of these two methods in StatusUpdater derived class destructor at the LATEST(!)
//to prevent access to callback to updater (e.g. request abort)
- void processHasFinished(SyncStatusID id, const zen::ErrorLog& log);
+ void processHasFinished(SyncResult resultId, const zen::ErrorLog& log); //sync finished, still dialog may live on
void closeWindowDirectly(); //don't wait for user
private:
diff --git a/ui/search.cpp b/ui/search.cpp
index af62686b..80e4aa26 100644
--- a/ui/search.cpp
+++ b/ui/search.cpp
@@ -17,16 +17,17 @@ using namespace zen;
class SearchDlg : public SearchDialogGenerated
{
public:
- SearchDlg(wxWindow& parentWindow, wxString& searchText, bool& respectCase);
+ SearchDlg(wxWindow* parent, wxString& searchText, bool& respectCase);
enum ReturnCodes
{
- BUTTON_OKAY = 1 //mustn't be 0
+ BUTTON_CANCEL,
+ BUTTON_OKAY
};
private:
- void OnClose (wxCloseEvent& event) { EndModal(0); }
- void OnCancel(wxCommandEvent& event) { EndModal(0); }
+ void OnClose (wxCloseEvent& event) { EndModal(BUTTON_CANCEL); }
+ void OnCancel(wxCommandEvent& event) { EndModal(BUTTON_CANCEL); }
void OnFindNext(wxCommandEvent& event);
void OnText(wxCommandEvent& event);
@@ -35,8 +36,8 @@ private:
};
-SearchDlg::SearchDlg(wxWindow& parentWindow, wxString& searchText, bool& respectCase) :
- SearchDialogGenerated(&parentWindow),
+SearchDlg::SearchDlg(wxWindow* parent, wxString& searchText, bool& respectCase) :
+ SearchDialogGenerated(parent),
searchText_(searchText),
respectCase_(respectCase)
{
@@ -47,7 +48,6 @@ SearchDlg::SearchDlg(wxWindow& parentWindow, wxString& searchText, bool& respect
m_checkBoxMatchCase->SetValue(respectCase_);
m_textCtrlSearchTxt->SetValue(searchText_);
- CentreOnParent(); //this requires a parent window!
m_textCtrlSearchTxt->SetFocus();
}
@@ -79,7 +79,7 @@ class FindInText
{
public:
FindInText(const wxString& textToFind) : textToFind_(textToFind) {}
- bool found(const wxString& phrase) const { return phrase.Find(textToFind_) != wxNOT_FOUND; }
+ bool found(const wxString& phrase) const { return contains(phrase, textToFind_); }
private:
wxString textToFind_;
@@ -95,7 +95,7 @@ public:
{
//wxWidgets::MakeUpper() is inefficient! But performance is not THAT important for this high-level search functionality
phrase.MakeUpper();
- return phrase.Find(textToFind_) != wxNOT_FOUND;
+ return contains(phrase, textToFind_);
}
private:
@@ -147,7 +147,7 @@ wxString lastSearchString; //this variable really is conceptionally global...
void executeSearch(bool forceShowDialog,
bool& respectCase,
- wxWindow& parentWindow,
+ wxWindow* parent,
Grid& grid,
size_t compPosLeft, size_t compPosRight)
{
@@ -155,7 +155,7 @@ void executeSearch(bool forceShowDialog,
if (forceShowDialog || lastSearchString.IsEmpty())
{
- SearchDlg searchDlg(parentWindow, lastSearchString, respectCase); //wxWidgets deletion handling -> deleted by parentWindow
+ SearchDlg searchDlg(parent, lastSearchString, respectCase); //wxWidgets deletion handling -> deleted by parentWindow
if (static_cast<SearchDlg::ReturnCodes>(searchDlg.ShowModal()) != SearchDlg::BUTTON_OKAY)
return;
@@ -195,24 +195,22 @@ void executeSearch(bool forceShowDialog,
return;
}
- wxString messageNotFound = _("Cannot find %x");
- messageNotFound.Replace(wxT("%x"), wxString(wxT("\"")) + lastSearchString + wxT("\""), false);
- wxMessageBox(messageNotFound, _("Find"), wxOK);
+ wxMessageBox(replaceCpy(_("Cannot find %x"), L"%x", L"\"" + lastSearchString + L"\"", false), _("Find"), wxOK, parent);
//show search dialog again
if (searchDialogWasShown)
- executeSearch(true, respectCase, parentWindow, grid, compPosLeft, compPosRight);
+ executeSearch(true, respectCase, parent, grid, compPosLeft, compPosRight);
}
//###########################################################################################
-void zen::startFind(wxWindow& parentWindow, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase) //Strg + F
+void zen::startFind(wxWindow* parent, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase) //Strg + F
{
- executeSearch(true, respectCase, parentWindow, grid, compPosLeft, compPosRight);
+ executeSearch(true, respectCase, parent, grid, compPosLeft, compPosRight);
}
-void zen::findNext(wxWindow& parentWindow, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase) //F3
+void zen::findNext(wxWindow* parent, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase) //F3
{
- executeSearch(false, respectCase, parentWindow, grid, compPosLeft, compPosRight);
+ executeSearch(false, respectCase, parent, grid, compPosLeft, compPosRight);
}
diff --git a/ui/search.h b/ui/search.h
index 1c26ea78..6120562e 100644
--- a/ui/search.h
+++ b/ui/search.h
@@ -11,8 +11,8 @@
namespace zen
{
-void startFind(wxWindow& parentWindow, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase); //Strg + F
-void findNext( wxWindow& parentWindow, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase); //F3
+void startFind(wxWindow* parent, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase); //Strg + F
+void findNext( wxWindow* parent, Grid& grid, size_t compPosLeft, size_t compPosRight, bool& respectCase); //F3
}
#endif // SEARCH_H_INCLUDED
diff --git a/ui/small_dlgs.cpp b/ui/small_dlgs.cpp
index 20e5da4e..c8c88de0 100644
--- a/ui/small_dlgs.cpp
+++ b/ui/small_dlgs.cpp
@@ -34,8 +34,8 @@ public:
AboutDlg(wxWindow* parent);
private:
- void OnClose(wxCloseEvent& event) { EndModal(0); }
- void OnOK (wxCommandEvent& event) { EndModal(0); }
+ void OnClose(wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnOK (wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_OKAY); }
};
@@ -72,22 +72,19 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
//build information
wxString build = __TDATE__;
#if wxUSE_UNICODE
- build += wxT(" - Unicode");
+ build += L" - Unicode";
#else
- build += wxT(" - ANSI");
+ build += L" - ANSI";
#endif //wxUSE_UNICODE
//compile time info about 32/64-bit build
if (zen::is64BitBuild)
- build += wxT(" x64");
+ build += L" x64";
else
- build += wxT(" x86");
+ build += L" x86";
assert_static(zen::is32BitBuild || zen::is64BitBuild);
- wxString buildFormatted = _("(Build: %x)");
- buildFormatted.Replace(wxT("%x"), build);
-
- m_build->SetLabel(buildFormatted);
+ m_build->SetLabel(replaceCpy(_("(Build: %x)"), L"%x", build));
//m_animationControl1->SetAnimation(GlobalResources::instance().animationMoney);
//m_animationControl1->Play();
@@ -101,9 +98,9 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
}
-void zen::showAboutDialog()
+void zen::showAboutDialog(wxWindow* parent)
{
- AboutDlg aboutDlg(nullptr);
+ AboutDlg aboutDlg(parent);
aboutDlg.ShowModal();
}
//########################################################################################
@@ -118,8 +115,8 @@ public:
~FilterDlg() {}
private:
- void OnClose ( wxCloseEvent& event) { EndModal(0); }
- void OnCancel (wxCommandEvent& event) { EndModal(0); }
+ void OnClose ( wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnCancel (wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
void OnHelp (wxCommandEvent& event);
void OnDefault (wxCommandEvent& event);
void OnApply (wxCommandEvent& event);
@@ -302,9 +299,9 @@ void FilterDlg::OnApply(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showFilterDialog(bool isGlobalFilter, FilterConfig& filter)
+ReturnSmallDlg::ButtonPressed zen::showFilterDialog(wxWindow* parent, bool isGlobalFilter, FilterConfig& filter)
{
- FilterDlg filterDlg(nullptr,
+ FilterDlg filterDlg(parent,
isGlobalFilter, //is main filter dialog
filter);
return static_cast<ReturnSmallDlg::ButtonPressed>(filterDlg.ShowModal());
@@ -417,12 +414,13 @@ void DeleteDialog::OnUseRecycler(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showDeleteDialog(const std::vector<zen::FileSystemObject*>& rowsOnLeft,
+ReturnSmallDlg::ButtonPressed zen::showDeleteDialog(wxWindow* parent,
+ const std::vector<zen::FileSystemObject*>& rowsOnLeft,
const std::vector<zen::FileSystemObject*>& rowsOnRight,
bool& deleteOnBothSides,
bool& useRecycleBin)
{
- DeleteDialog confirmDeletion(nullptr,
+ DeleteDialog confirmDeletion(parent,
rowsOnLeft,
rowsOnRight,
deleteOnBothSides,
@@ -440,15 +438,14 @@ public:
const zen::SyncStatistics& statistics,
bool& dontShowAgain);
private:
- void OnClose(wxCloseEvent& event);
- void OnCancel(wxCommandEvent& event);
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
void OnStartSync(wxCommandEvent& event);
bool& m_dontShowAgain;
};
-
SyncPreviewDlg::SyncPreviewDlg(wxWindow* parent,
const wxString& variantName,
const zen::SyncStatistics& statistics,
@@ -487,18 +484,6 @@ SyncPreviewDlg::SyncPreviewDlg(wxWindow* parent,
}
-void SyncPreviewDlg::OnClose(wxCloseEvent& event)
-{
- EndModal(ReturnSmallDlg::BUTTON_CANCEL);
-}
-
-
-void SyncPreviewDlg::OnCancel(wxCommandEvent& event)
-{
- EndModal(ReturnSmallDlg::BUTTON_CANCEL);
-}
-
-
void SyncPreviewDlg::OnStartSync(wxCommandEvent& event)
{
m_dontShowAgain = m_checkBoxDontShowAgain->GetValue();
@@ -506,12 +491,12 @@ void SyncPreviewDlg::OnStartSync(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showSyncPreviewDlg(
- const wxString& variantName,
- const zen::SyncStatistics& statistics,
- bool& dontShowAgain)
+ReturnSmallDlg::ButtonPressed zen::showSyncPreviewDlg(wxWindow* parent,
+ const wxString& variantName,
+ const zen::SyncStatistics& statistics,
+ bool& dontShowAgain)
{
- SyncPreviewDlg preview(nullptr,
+ SyncPreviewDlg preview(parent,
variantName,
statistics,
dontShowAgain);
@@ -524,13 +509,12 @@ ReturnSmallDlg::ButtonPressed zen::showSyncPreviewDlg(
class CompareCfgDialog : public CmpCfgDlgGenerated
{
public:
- CompareCfgDialog(wxWindow* parent,
- CompConfig& cmpConfig);
+ CompareCfgDialog(wxWindow* parent, CompConfig& cmpConfig);
private:
void OnOkay(wxCommandEvent& event);
- void OnClose(wxCloseEvent& event) { EndModal(0); }
- void OnCancel(wxCommandEvent& event) { EndModal(0); }
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
void OnShowHelp(wxCommandEvent& event);
void OnTimeSize(wxCommandEvent& event) { m_radioBtnSizeDate->SetValue(true); }
@@ -632,10 +616,9 @@ void CompareCfgDialog::OnShowHelp(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showCompareCfgDialog(CompConfig& cmpConfig)
+ReturnSmallDlg::ButtonPressed zen::showCompareCfgDialog(wxWindow* parent, CompConfig& cmpConfig)
{
- CompareCfgDialog syncDlg(nullptr, cmpConfig);
-
+ CompareCfgDialog syncDlg(parent, cmpConfig);
return static_cast<ReturnSmallDlg::ButtonPressed>(syncDlg.ShowModal());
}
//########################################################################################
@@ -650,8 +633,8 @@ private:
void OnOkay(wxCommandEvent& event);
void OnResetDialogs(wxCommandEvent& event);
void OnDefault(wxCommandEvent& event);
- void OnCancel(wxCommandEvent& event);
- void OnClose(wxCloseEvent& event);
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
void OnAddRow(wxCommandEvent& event);
void OnRemoveRow(wxCommandEvent& event);
void OnResize(wxSizeEvent& event);
@@ -741,7 +724,7 @@ void GlobalSettingsDlg::OnOkay(wxCommandEvent& event)
void GlobalSettingsDlg::OnResetDialogs(wxCommandEvent& event)
{
- if (showQuestionDlg(ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_CANCEL,
+ if (showQuestionDlg(this, ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_CANCEL,
_("Make hidden dialogs and warning messages visible again?")) == ReturnQuestionDlg::BUTTON_YES)
settings.optDialogs.resetDialogs();
}
@@ -758,18 +741,6 @@ void GlobalSettingsDlg::OnDefault(wxCommandEvent& event)
}
-void GlobalSettingsDlg::OnCancel(wxCommandEvent& event)
-{
- EndModal(0);
-}
-
-
-void GlobalSettingsDlg::OnClose(wxCloseEvent& event)
-{
- EndModal(0);
-}
-
-
void GlobalSettingsDlg::set(const xmlAccess::ExternalApps& extApp)
{
auto extAppTmp = extApp;
@@ -835,9 +806,9 @@ void GlobalSettingsDlg::OnRemoveRow(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showGlobalSettingsDlg(xmlAccess::XmlGlobalSettings& globalSettings)
+ReturnSmallDlg::ButtonPressed zen::showGlobalSettingsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings)
{
- GlobalSettingsDlg settingsDlg(nullptr, globalSettings);
+ GlobalSettingsDlg settingsDlg(parent, globalSettings);
return static_cast<ReturnSmallDlg::ButtonPressed>(settingsDlg.ShowModal());
}
//########################################################################################
@@ -850,8 +821,8 @@ public:
private:
void OnOkay(wxCommandEvent& event);
- void OnCancel(wxCommandEvent& event) { EndModal(0); }
- void OnClose(wxCloseEvent& event) { EndModal(0); }
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
virtual void OnChangeSelectionFrom(wxCalendarEvent& event)
{
@@ -960,8 +931,8 @@ void SelectTimespanDlg::OnOkay(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showSelectTimespanDlg(Int64& timeFrom, Int64& timeTo)
+ReturnSmallDlg::ButtonPressed zen::showSelectTimespanDlg(wxWindow* parent, Int64& timeFrom, Int64& timeTo)
{
- SelectTimespanDlg timeSpanDlg(nullptr, timeFrom, timeTo);
+ SelectTimespanDlg timeSpanDlg(parent, timeFrom, timeTo);
return static_cast<ReturnSmallDlg::ButtonPressed>(timeSpanDlg.ShowModal());
}
diff --git a/ui/small_dlgs.h b/ui/small_dlgs.h
index b42f56eb..98a072cf 100644
--- a/ui/small_dlgs.h
+++ b/ui/small_dlgs.h
@@ -13,6 +13,8 @@
namespace zen
{
+//parent window, optional: support correct dialog placement above parent on multiple monitor systems
+
struct ReturnSmallDlg
{
enum ButtonPressed
@@ -22,27 +24,26 @@ struct ReturnSmallDlg
};
};
+void showAboutDialog(wxWindow* parent);
-void showAboutDialog();
-
-ReturnSmallDlg::ButtonPressed showFilterDialog(bool isGlobalFilter, FilterConfig& filter);
+ReturnSmallDlg::ButtonPressed showFilterDialog(wxWindow* parent, bool isGlobalFilter, FilterConfig& filter);
-ReturnSmallDlg::ButtonPressed showDeleteDialog(
- const std::vector<FileSystemObject*>& rowsOnLeft,
- const std::vector<FileSystemObject*>& rowsOnRight,
- bool& deleteOnBothSides,
- bool& useRecycleBin);
+ReturnSmallDlg::ButtonPressed showDeleteDialog(wxWindow* parent,
+ const std::vector<FileSystemObject*>& rowsOnLeft,
+ const std::vector<FileSystemObject*>& rowsOnRight,
+ bool& deleteOnBothSides,
+ bool& useRecycleBin);
-ReturnSmallDlg::ButtonPressed showSyncPreviewDlg(
- const wxString& variantName,
- const SyncStatistics& statistics,
- bool& dontShowAgain);
+ReturnSmallDlg::ButtonPressed showSyncPreviewDlg(wxWindow* parent,
+ const wxString& variantName,
+ const SyncStatistics& statistics,
+ bool& dontShowAgain);
-ReturnSmallDlg::ButtonPressed showCompareCfgDialog(CompConfig& cmpConfig);
+ReturnSmallDlg::ButtonPressed showCompareCfgDialog(wxWindow* parent, CompConfig& cmpConfig);
-ReturnSmallDlg::ButtonPressed showGlobalSettingsDlg(xmlAccess::XmlGlobalSettings& globalSettings);
+ReturnSmallDlg::ButtonPressed showGlobalSettingsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings);
-ReturnSmallDlg::ButtonPressed showSelectTimespanDlg(Int64& timeFrom, Int64& timeTo);
+ReturnSmallDlg::ButtonPressed showSelectTimespanDlg(wxWindow* parent, Int64& timeFrom, Int64& timeTo);
}
#endif // SMALLDIALOGS_H_INCLUDED
diff --git a/ui/sorting.h b/ui/sorting.h
index 807a9ce3..ad54bfbe 100644
--- a/ui/sorting.h
+++ b/ui/sorting.h
@@ -156,16 +156,19 @@ bool lessExtension(const FileSystemObject& a, const FileSystemObject& b)
else if (b.isEmpty<side>())
return true; //empty rows always last
-
- const FileMapping* fileObjA = dynamic_cast<const FileMapping*>(&a);
- const FileMapping* fileObjB = dynamic_cast<const FileMapping*>(&b);
-
- if (!fileObjA)
+ if (dynamic_cast<const DirMapping*>(&a))
return false; //directories last
- else if (!fileObjB)
+ else if (dynamic_cast<const DirMapping*>(&b))
return true; //directories last
- return makeSortDirection(LessFilename(), Int2Type<ascending>())(fileObjA->getExtension<side>(), fileObjB->getExtension<side>());
+ auto getExtension = [&](const FileSystemObject& fsObj) -> Zstring
+ {
+ const Zstring& shortName = fsObj.getShortName<side>();
+ const size_t pos = shortName.rfind(Zchar('.'));
+ return pos == Zstring::npos ? Zstring() : Zstring(shortName.c_str() + pos + 1);
+ };
+
+ return makeSortDirection(LessFilename(), Int2Type<ascending>())(getExtension(a), getExtension(b));
}
diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp
index 4f6df013..87e1b44d 100644
--- a/ui/sync_cfg.cpp
+++ b/ui/sync_cfg.cpp
@@ -26,7 +26,7 @@ using namespace xmlAccess;
class SyncCfgDialog : public SyncCfgDlgGenerated
{
public:
- SyncCfgDialog(wxWindow* window,
+ SyncCfgDialog(wxWindow* parent,
CompareVariant compareVar,
SyncConfig& syncCfg,
xmlAccess::OnGuiError* handleError, //
@@ -50,9 +50,9 @@ private:
virtual void OnDifferent( wxCommandEvent& event);
virtual void OnConflict( wxCommandEvent& event);
- virtual void OnClose( wxCloseEvent& event) { EndModal(0); }
- virtual void OnCancel( wxCommandEvent& event) { EndModal(0); }
- virtual void OnApply( wxCommandEvent& event);
+ virtual void OnClose (wxCloseEvent& event) { EndModal(ReturnSyncConfig::BUTTON_CANCEL); }
+ virtual void OnCancel(wxCommandEvent& event) { EndModal(ReturnSyncConfig::BUTTON_CANCEL); }
+ virtual void OnApply (wxCommandEvent& event);
void updateGui();
@@ -194,12 +194,12 @@ void updateConfigIcons(const DirectionConfig& directionCfg,
}
-SyncCfgDialog::SyncCfgDialog(wxWindow* window,
+SyncCfgDialog::SyncCfgDialog(wxWindow* parent,
CompareVariant compareVar,
SyncConfig& syncCfg,
xmlAccess::OnGuiError* handleError,
ExecWhenFinishedCfg* execWhenFinished) :
- SyncCfgDlgGenerated(window),
+ SyncCfgDlgGenerated(parent),
cmpVariant(compareVar),
currentDirectionCfg(syncCfg.directionCfg), //make working copy
syncCfgOut(syncCfg),
@@ -529,12 +529,13 @@ void SyncCfgDialog::OnConflict(wxCommandEvent& event)
}
-ReturnSyncConfig::ButtonPressed zen::showSyncConfigDlg(CompareVariant compareVar,
+ReturnSyncConfig::ButtonPressed zen::showSyncConfigDlg(wxWindow* parent,
+ CompareVariant compareVar,
SyncConfig& syncCfg,
xmlAccess::OnGuiError* handleError, //
ExecWhenFinishedCfg* execWhenFinished) //optional input parameter
{
- SyncCfgDialog syncDlg(nullptr,
+ SyncCfgDialog syncDlg(parent,
compareVar,
syncCfg,
handleError,
diff --git a/ui/sync_cfg.h b/ui/sync_cfg.h
index dae79d1d..3d5eb88c 100644
--- a/ui/sync_cfg.h
+++ b/ui/sync_cfg.h
@@ -7,8 +7,10 @@
#ifndef SYNCCONFIG_H_INCLUDED
#define SYNCCONFIG_H_INCLUDED
+#include <wx/window.h>
#include "../lib/process_xml.h"
+
namespace zen
{
struct ReturnSyncConfig
@@ -16,7 +18,7 @@ struct ReturnSyncConfig
enum ButtonPressed
{
BUTTON_CANCEL,
- BUTTON_OKAY = 1
+ BUTTON_OKAY
};
};
@@ -28,7 +30,8 @@ struct ExecWhenFinishedCfg
};
-ReturnSyncConfig::ButtonPressed showSyncConfigDlg(CompareVariant compareVar,
+ReturnSyncConfig::ButtonPressed showSyncConfigDlg(wxWindow* parent,
+ CompareVariant compareVar,
SyncConfig& syncCfg,
xmlAccess::OnGuiError* handleError, //
ExecWhenFinishedCfg* execWhenFinished); //optional input parameter
diff --git a/ui/taskbar.cpp b/ui/taskbar.cpp
index 7219be14..0611d739 100644
--- a/ui/taskbar.cpp
+++ b/ui/taskbar.cpp
@@ -24,7 +24,7 @@ using namespace zen;
using namespace tbseven;
-class Taskbar::Pimpl //throw (TaskbarNotAvailable)
+class Taskbar::Pimpl //throw TaskbarNotAvailable
{
public:
Pimpl(const wxTopLevelWindow& window) :
@@ -145,7 +145,7 @@ public:
//########################################################################################################
Taskbar::Taskbar(const wxTopLevelWindow& window) : pimpl_(new Pimpl(window)) {} //throw TaskbarNotAvailable
-Taskbar::~Taskbar() {} //std::unique_ptr ...
+Taskbar::~Taskbar() {}
void Taskbar::setStatus(Status status) { pimpl_->setStatus(status); }
void Taskbar::setProgress(double fraction) { pimpl_->setProgress(fraction); }
diff --git a/ui/taskbar.h b/ui/taskbar.h
index bf40adde..048bf9e8 100644
--- a/ui/taskbar.h
+++ b/ui/taskbar.h
@@ -11,7 +11,7 @@
#include <wx/toplevel.h>
/*
-Windows 7; show progress in windows superbar via ITaskbarList3 Interface (http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx)
+Windows 7; show progress in windows superbar via ITaskbarList3 Interface: http://msdn.microsoft.com/en-us/library/dd391692(VS.85).aspx
Ubuntu: use Unity interface (optional)
diff --git a/ui/tray_icon.cpp b/ui/tray_icon.cpp
index 51441e36..2fc76f15 100644
--- a/ui/tray_icon.cpp
+++ b/ui/tray_icon.cpp
@@ -185,9 +185,10 @@ private:
FfsTrayIcon::FfsTrayIcon() :
- trayIcon(new TaskBarImpl(*this))
+ trayIcon(new TaskBarImpl(*this)),
+ fractionLast(1) //show FFS logo by default
{
- trayIcon->SetIcon(generateIcon(0), wxT("FreeFileSync"));
+ trayIcon->SetIcon(generateIcon(fractionLast), L"FreeFileSync");
trayIcon->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(FfsTrayIcon::OnDoubleClick), nullptr, this); //register double-click
}
@@ -204,23 +205,30 @@ FfsTrayIcon::~FfsTrayIcon()
}
-void FfsTrayIcon::setToolTip(const wxString& toolTipText, double fraction)
+void FfsTrayIcon::setToolTip(const wxString& toolTip)
{
- trayIcon->SetIcon(generateIcon(fraction), toolTipText);
+ toolTipLast = toolTip;
+ trayIcon->SetIcon(generateIcon(fractionLast), toolTip); //another wxWidgets design bug: non-orthogonal method!
+}
+
+
+void FfsTrayIcon::setProgress(double fraction)
+{
+ fractionLast = fraction;
+ trayIcon->SetIcon(generateIcon(fraction), toolTipLast);
}
void FfsTrayIcon::OnContextMenuSelection(wxCommandEvent& event)
{
- const Selection eventId = static_cast<Selection>(event.GetId());
- switch (eventId)
+ switch (static_cast<Selection>(event.GetId()))
{
case CONTEXT_ABOUT:
{
//ATTENTION: the modal dialog below does NOT disable all GUI input, e.g. user may still double-click on tray icon
//which will implicitly destroy the tray icon while still showing the modal dialog
trayIcon->SetEvtHandlerEnabled(false);
- zen::showAboutDialog();
+ zen::showAboutDialog(nullptr);
trayIcon->SetEvtHandlerEnabled(true);
}
break;
diff --git a/ui/tray_icon.h b/ui/tray_icon.h
index d1522602..50480b54 100644
--- a/ui/tray_icon.h
+++ b/ui/tray_icon.h
@@ -19,7 +19,8 @@ public:
FfsTrayIcon();
~FfsTrayIcon();
- void setToolTip(const wxString& toolTipText, double fraction = 0); //number between [0, 1], for small progress indicator
+ void setToolTip(const wxString& toolTip);
+ void setProgress(double fraction); //number between [0, 1], for small progress indicator
private:
FfsTrayIcon(const FfsTrayIcon&);
@@ -30,6 +31,9 @@ private:
class TaskBarImpl;
TaskBarImpl* trayIcon; //actual tray icon (don't use inheritance to enable delayed deletion)
+
+ wxString toolTipLast;
+ double fractionLast;
};
#endif // TRAYICON_H_INCLUDED
diff --git a/ui/tree_view.cpp b/ui/tree_view.cpp
index 49548142..b3a9595a 100644
--- a/ui/tree_view.cpp
+++ b/ui/tree_view.cpp
@@ -23,10 +23,10 @@ inline
void TreeView::compressNode(Container& cont) //remove single-element sub-trees -> gain clarity + usability (call *after* inclusion check!!!)
{
if (cont.subDirs.empty() || //single files node or...
- (cont.firstFile == nullptr && //single dir node...
- cont.subDirs.size() == 1 && //
+ (cont.firstFile == nullptr && //single dir node...
+ cont.subDirs.size() == 1 && //
cont.subDirs[0].firstFile == nullptr && //...that is empty
- cont.subDirs[0].subDirs.empty())) //
+ cont.subDirs[0].subDirs.empty())) //
{
cont.subDirs.clear();
cont.firstFile = nullptr;
@@ -624,7 +624,7 @@ public:
fileIcon(IconBuffer(IconBuffer::SIZE_SMALL).genericFileIcon()),
dirIcon (IconBuffer(IconBuffer::SIZE_SMALL).genericDirIcon ()),
rootBmp(GlobalResources::getImage(L"rootFolder").ConvertToImage().Scale(fileIcon.GetWidth(), fileIcon.GetHeight(), wxIMAGE_QUALITY_HIGH)),
- widthNodeIcon(fileIcon.GetWidth()),
+ widthNodeIcon(dirIcon.GetWidth()),
widthLevelStep(widthNodeIcon),
widthNodeStatus(GlobalResources::getImage(L"nodeExpanded").GetWidth()),
grid_(grid),
diff --git a/ui/tree_view.h b/ui/tree_view.h
index 3bb741e6..01c737bc 100644
--- a/ui/tree_view.h
+++ b/ui/tree_view.h
@@ -151,7 +151,7 @@ private:
/* /|\
| (update...)
| */
- std::vector<RootNodeImpl> folderCmpView; //partial view on folderCmp -> unsorted(cannot be, because of files!)
+ std::vector<RootNodeImpl> folderCmpView; //partial view on folderCmp -> unsorted (cannot be, because files are not a separate entity)
/* /|\
| (update...)
| */
diff --git a/version/version.h b/version/version.h
index de76a783..4bb5c71a 100644
--- a/version/version.h
+++ b/version/version.h
@@ -3,7 +3,7 @@
namespace zen
{
- const wchar_t currentVersion[] = L"5.2"; //internal linkage!
+const wchar_t currentVersion[] = L"5.3"; //internal linkage!
}
#endif
diff --git a/version/version.rc b/version/version.rc
index d43c8cb0..a440442d 100644
--- a/version/version.rc
+++ b/version/version.rc
@@ -1,2 +1,2 @@
-#define VER_FREEFILESYNC 5,2,0,0
-#define VER_FREEFILESYNC_STR "5.2\0"
+#define VER_FREEFILESYNC 5,3,0,0
+#define VER_FREEFILESYNC_STR "5.3\0"
diff --git a/wx+/context_menu.h b/wx+/context_menu.h
index 8f80fac2..663596f9 100644
--- a/wx+/context_menu.h
+++ b/wx+/context_menu.h
@@ -7,6 +7,7 @@
#ifndef CONTEXT_HEADER_18047302153418174632141234
#define CONTEXT_HEADER_18047302153418174632141234
+#include <map>
#include <vector>
#include <functional>
#include <wx/menu.h>
@@ -17,7 +18,7 @@ A context menu supporting C++11 lambda callbacks!
Usage:
ContextMenu menu;
- menu.addItem(L"Some Label", [&]{ ...do something... }); -> capture by reference is fine, as long as captured variables have at least scope of ContextMenu::show()!
+ menu.addItem(L"Some Label", [&]{ ...do something... }); -> capture by reference is fine, as long as captured variables have at least scope of ContextMenu::popup()!
...
menu.popup(wnd);
*/
@@ -27,36 +28,52 @@ namespace zen
class ContextMenu : private wxEvtHandler
{
public:
+ ContextMenu() : menu(new wxMenu) {}
+
void addItem(const wxString& label, const std::function<void()>& command, const wxBitmap* bmp = nullptr, bool enabled = true)
{
- wxMenuItem* newItem = new wxMenuItem(&menu, wxID_ANY, label);
+ wxMenuItem* newItem = new wxMenuItem(menu.get(), wxID_ANY, label); //menu owns item!
if (bmp) newItem->SetBitmap(*bmp); //do not set AFTER appending item! wxWidgets screws up for yet another crappy reason
- menu.Append(newItem);
+ menu->Append(newItem);
if (!enabled) newItem->Enable(false); //do not enable BEFORE appending item! wxWidgets screws up for yet another crappy reason
- menu.Connect(newItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(command), /*pass ownership*/ this);
+ commandList[newItem->GetId()] = command; //defer event connection, this may be a submenu only!
}
void addCheckBox(const wxString& label, const std::function<void()>& command, bool checked, bool enabled = true)
{
- wxMenuItem* newItem = menu.AppendCheckItem(wxID_ANY, label);
+ wxMenuItem* newItem = menu->AppendCheckItem(wxID_ANY, label);
newItem->Check(checked);
if (!enabled) newItem->Enable(false);
- menu.Connect(newItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(command), /*pass ownership*/ this);
+ commandList[newItem->GetId()] = command;
}
void addRadio(const wxString& label, const std::function<void()>& command, bool checked, bool enabled = true)
{
- wxMenuItem* newItem = menu.AppendRadioItem(wxID_ANY, label);
+ wxMenuItem* newItem = menu->AppendRadioItem(wxID_ANY, label);
newItem->Check(checked);
if (!enabled) newItem->Enable(false);
- menu.Connect(newItem->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(command), /*pass ownership*/ this);
+ commandList[newItem->GetId()] = command;
}
- void addSeparator() { menu.AppendSeparator(); }
+ void addSeparator() { menu->AppendSeparator(); }
+
+ void addSubmenu(const wxString& label, ContextMenu& submenu, const wxBitmap* bmp = nullptr) //invalidates submenu!
+ {
+ wxMenuItem* newItem = new wxMenuItem(menu.get(), wxID_ANY, label, L"", wxITEM_NORMAL, submenu.menu.release()); //menu owns item!
+ if (bmp) newItem->SetBitmap(*bmp); //do not set AFTER appending item! wxWidgets screws up for yet another crappy reason
+ menu->Append(newItem);
+ //transfer submenu commands:
+ commandList.insert(submenu.commandList.begin(), submenu.commandList.end());
+ submenu.commandList.clear();
+ }
void popup(wxWindow& wnd) //show popup menu + process lambdas
{
- wnd.PopupMenu(&menu);
+ //eventually all events from submenu items will be received by this menu
+ for (auto iter = commandList.begin(); iter != commandList.end(); ++iter)
+ menu->Connect(iter->first, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(ContextMenu::onSelection), new GenericCommand(iter->second), /*pass ownership*/ this);
+
+ wnd.PopupMenu(menu.get());
wxTheApp->ProcessPendingEvents(); //make sure lambdas are evaluated before going out of scope;
//although all events seem to be processed within wxWindows::PopupMenu, we shouldn't trust wxWidgets in this regard
}
@@ -74,7 +91,8 @@ private:
std::function<void()> fun_;
};
- wxMenu menu;
+ std::unique_ptr<wxMenu> menu;
+ std::map<int, std::function<void()>> commandList; //(item id, command)
};
}
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index 185121f1..9a64b3dd 100644
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -411,7 +411,8 @@ void Graph2D::render(wxDC& dc) const
if (iter->first.get())
{
const GraphData& graph = *iter->first;
- assert(graph.getXBegin() <= graph.getXEnd());
+ assert(graph.getXBegin() <= graph.getXEnd() + 1.0e-9);
+ //GCC fucks up bad when comparing two *binary identical* doubles and finds "begin > end" with diff of 1e-18
if (attr.minXauto)
minWndX = std::min(minWndX, graph.getXBegin());
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index 10e427ef..89891879 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -6,7 +6,6 @@
#include "grid.h"
#include <cassert>
-#include <ctime>
#include <set>
#include <wx/dcbuffer.h> //for macro: wxALWAYS_NATIVE_DOUBLE_BUFFER
#include <wx/settings.h>
@@ -14,6 +13,7 @@
#include <wx/tooltip.h>
#include <wx/timer.h>
#include <wx/utils.h>
+#include <zen/tick_count.h>
#include <zen/string_tools.h>
#include <zen/scope_guard.h>
#include "format_unit.h"
@@ -1257,7 +1257,9 @@ private:
{
public:
MouseSelection(MainWin& wnd, ptrdiff_t rowStart, size_t compPos, bool positiveSelect) :
- wnd_(wnd), rowStart_(rowStart), compPos_(compPos), rowCurrent_(rowStart), positiveSelect_(positiveSelect), toScrollX(0), toScrollY(0), tickCountLast(clock())
+ wnd_(wnd), rowStart_(rowStart), compPos_(compPos), rowCurrent_(rowStart), positiveSelect_(positiveSelect), toScrollX(0), toScrollY(0),
+ tickCountLast(getTicks()),
+ ticksPerSec_(ticksPerSec())
{
wnd_.CaptureMouse();
timer.Connect(wxEVT_TIMER, wxEventHandler(MouseSelection::onTimer), nullptr, this);
@@ -1273,9 +1275,13 @@ private:
void evalMousePos()
{
- const clock_t now = std::clock();
- const double deltaTime = static_cast<double>(now - tickCountLast) / CLOCKS_PER_SEC; //unit: [sec]
- tickCountLast = now;
+ double deltaTime = 0;
+ if (ticksPerSec_ > 0)
+ {
+ const TickVal now = getTicks(); //0 on error
+ deltaTime = static_cast<double>(now - tickCountLast) / ticksPerSec_; //unit: [sec]
+ tickCountLast = now;
+ }
wxMouseState mouseState = wxGetMouseState();
const wxPoint clientPos = wnd_.ScreenToClient(wxPoint(mouseState.GetX(), mouseState.GetY()));
@@ -1345,7 +1351,8 @@ private:
wxTimer timer;
double toScrollX; //count outstanding scroll units to scroll while dragging mouse
double toScrollY; //
- clock_t tickCountLast;
+ TickVal tickCountLast;
+ const std::int64_t ticksPerSec_;
};
virtual void ScrollWindow(int dx, int dy, const wxRect* rect)
@@ -1853,6 +1860,8 @@ void Grid::selectRange(ptrdiff_t rowFrom, ptrdiff_t rowTo, size_t compPos, bool
GridRangeSelectEvent selectionEvent(rowFrom, rowTo, compPos, positive);
if (wxEvtHandler* evtHandler = GetEventHandler())
evtHandler->ProcessEvent(selectionEvent);
+
+ mainWin_->Refresh();
}
}
diff --git a/wx+/serialize.h b/wx+/serialize.h
index b6a478cd..f49bff04 100644
--- a/wx+/serialize.h
+++ b/wx+/serialize.h
@@ -15,10 +15,12 @@
namespace zen
{
//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);
template <class S> S readString (wxInputStream& stream);
+template <class S> void readString (wxInputStream& stream, S& str);
template <class S> void writeString(wxOutputStream& stream, const S& str);
@@ -53,6 +55,9 @@ private:
class CheckedIo
{
+public:
+ virtual void throwException() const = 0;
+
protected:
CheckedIo(wxStreamBase& stream) : stream_(stream) {}
@@ -61,7 +66,6 @@ protected:
if (stream_.GetLastError() != wxSTREAM_NO_ERROR)
throwException();
}
- virtual void throwException() const = 0;
private:
wxStreamBase& stream_;
@@ -69,7 +73,7 @@ private:
//wxInputStream proxy throwing exception on error
-class CheckedReader : private CheckedIo
+class CheckedReader : public CheckedIo
{
public:
CheckedReader(wxInputStream& stream) : CheckedIo(stream), stream_(stream) {}
@@ -77,26 +81,36 @@ public:
template <class T>
T readPOD() const; //throw!
+ template <class T>
+ void readPOD(T& pod) const; //throw!
+
template <class S>
S readString() const; //throw!
+ template <class S>
+ void readString(S& str) const; //throw!
+
+ void readArray(void* data, size_t len) const; //throw!
+
private:
wxInputStream& stream_;
};
//wxOutputStream proxy throwing FileError on error
-class CheckedWriter : private CheckedIo
+class CheckedWriter : public CheckedIo
{
public:
CheckedWriter(wxOutputStream& stream) : CheckedIo(stream), stream_(stream) {}
template <class T>
- void writePOD(T number) const; //throw!
+ void writePOD(const T& pod) const; //throw!
template <class S>
void writeString(const S& str) const; //throw!
+ void writeArray(const void* data, size_t len) const; //throw!
+
private:
wxOutputStream& stream_;
};
@@ -129,12 +143,19 @@ template <class T> inline
T readPOD(wxInputStream& stream)
{
T pod = 0;
- stream.Read(reinterpret_cast<char*>(&pod), sizeof(T));
+ readPOD(stream, pod);
return pod;
}
template <class T> inline
+void readPOD(wxInputStream& stream, T& pod)
+{
+ stream.Read(reinterpret_cast<char*>(&pod), sizeof(T));
+}
+
+
+template <class T> inline
void writePOD(wxOutputStream& stream, const T& pod)
{
stream.Write(reinterpret_cast<const char*>(&pod), sizeof(T));
@@ -144,64 +165,96 @@ void writePOD(wxOutputStream& stream, const T& pod)
template <class S> inline
S readString(wxInputStream& stream)
{
- //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data!
+ S str;
+ readString(stream, str);
+ return str;
+}
- typedef typename S::value_type CharType;
+
+template <class S> inline
+void readString(wxInputStream& stream, S& str)
+{
+ //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data!
const auto strLength = readPOD<std::uint32_t>(stream);
- S output;
+ str.resize(strLength); //throw std::bad_alloc
if (strLength > 0)
- {
- output.resize(strLength); //throw std::bad_alloc
- stream.Read(&*output.begin(), sizeof(CharType) * strLength);
- }
- return output;
+ stream.Read(&*str.begin(), sizeof(typename S::value_type) * strLength);
}
template <class S> inline
void writeString(wxOutputStream& stream, const S& str)
{
- writePOD(stream, static_cast<std::uint32_t>(str.length()));
- stream.Write(str.c_str(), sizeof(typename S::value_type) * str.length());
+ const auto strLength = str.length();
+ writePOD(stream, static_cast<std::uint32_t>(strLength));
+ if (strLength > 0)
+ stream.Write(&*str.begin(), sizeof(typename S::value_type) * strLength); //don't use c_str(), but access uniformly via STL interface
}
-template <class T>
inline
-T CheckedReader::readPOD() const //checked read operation
+void CheckedReader::readArray(void* data, size_t len) const //throw!
{
- T output = zen::readPOD<T>(stream_);
+ stream_.Read(data, len);
check();
- return output;
+}
+
+
+template <class T> inline
+T CheckedReader::readPOD() const //checked read operation
+{
+ T pod = 0;
+ readPOD(pod);
+ return pod;
+}
+
+
+template <class T> inline
+void CheckedReader::readPOD(T& pod) const //checked read operation
+{
+ readArray(&pod, sizeof(T));
}
template <class S> inline
S CheckedReader::readString() const //checked read operation
{
- S output;
+ S str;
+ readString(str);
+ return str;
+}
+
+
+template <class S> inline
+void CheckedReader::readString(S& str) const //checked read operation
+{
try
{
- output = zen::readString<S>(stream_); //throw std::bad_alloc
+ zen::readString<S>(stream_, str); //throw std::bad_alloc
}
catch (std::exception&) { throwException(); }
-
check();
- if (stream_.LastRead() != output.length() * sizeof(typename S::value_type)) //some additional check
+ if (stream_.LastRead() != str.length() * sizeof(typename S::value_type)) //some additional check
throwException();
- return output;
}
-template <class T> inline
-void CheckedWriter::writePOD(T number) const //checked write operation
+inline
+void CheckedWriter::writeArray(const void* data, size_t len) const //throw!
{
- zen::writePOD<T>(stream_, number);
+ stream_.Write(data, len);
check();
}
+template <class T> inline
+void CheckedWriter::writePOD(const T& pod) const //checked write opera
+{
+ writeArray(&pod, sizeof(T));
+}
+
+
template <class S> inline
void CheckedWriter::writeString(const S& str) const //checked write operation
{
diff --git a/wx+/shell_execute.h b/wx+/shell_execute.h
index 3468a1c8..9de30980 100644
--- a/wx+/shell_execute.h
+++ b/wx+/shell_execute.h
@@ -14,10 +14,12 @@
#include <zen/string_tools.h>
#include <zen/i18n.h>
#include <zen/win.h> //includes "windows.h"
+//#include <zen/scope_guard.h>
#elif defined FFS_LINUX
#include <stdlib.h>
#include <wx/utils.h>
+#include <wx/log.h>
#endif
@@ -38,11 +40,10 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
#ifdef FFS_WIN
//parse commandline
std::vector<std::wstring> argv;
+ int argc = 0;
+ if (LPWSTR* tmp = ::CommandLineToArgvW(command.c_str(), &argc))
{
- int argc = 0;
- LPWSTR* tmp = ::CommandLineToArgvW(command.c_str(), &argc);
- for (int i = 0; i < argc; ++i)
- argv.push_back(tmp[i]);
+ std::copy(tmp, tmp + argc, std::back_inserter(argv));
::LocalFree(tmp);
}
@@ -57,44 +58,38 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
}
SHELLEXECUTEINFO execInfo = {};
- execInfo.cbSize = sizeof(execInfo);
+ execInfo.cbSize = sizeof(execInfo);
//SEE_MASK_NOASYNC is equal to SEE_MASK_FLAG_DDEWAIT, but former is defined not before Win SDK 6.0
execInfo.fMask = type == EXEC_TYPE_SYNC ? (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT) : 0; //don't use SEE_MASK_ASYNCOK -> returns successful despite errors!
execInfo.fMask |= SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; //::ShellExecuteEx() shows a non-blocking pop-up dialog on errors -> we want a blocking one
- execInfo.lpVerb = L"open";
+ execInfo.lpVerb = nullptr;
execInfo.lpFile = filename.c_str();
execInfo.lpParameters = arguments.c_str();
execInfo.nShow = SW_SHOWNORMAL;
if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo
{
- wxString errorMsg = _("Invalid command line: %x");
- wxString cmdFmt = wxString(L"\nFile: ") + filename + L"\nArg: " + arguments;
-
- errorMsg.Replace(L"%x", cmdFmt);
- wxMessageBox(errorMsg + L"\n\n" + getLastErrorFormatted());
+ wxString cmdFmt = L"File: " + filename + L"\nArg: " + arguments;
+ wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\n" + cmdFmt) + L"\n\n" + getLastErrorFormatted());
return;
}
- if (type == EXEC_TYPE_SYNC)
+ if (execInfo.hProcess)
{
- if (execInfo.hProcess != 0)
- {
+ if (type == EXEC_TYPE_SYNC)
::WaitForSingleObject(execInfo.hProcess, INFINITE);
- ::CloseHandle(execInfo.hProcess);
- }
+ ::CloseHandle(execInfo.hProcess);
}
#elif defined FFS_LINUX
if (type == EXEC_TYPE_SYNC)
{
+ //Posix::system - execute a shell command
int rv = ::system(utf8CvrtTo<std::string>(command).c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
if (rv == -1 || WEXITSTATUS(rv) == 127) //http://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)"
{
- wxString errorMsg = _("Invalid command line: %x");
- replace(errorMsg, L"%x", L"\n" + command);
- wxMessageBox(errorMsg);
+ wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\n" + command));
return;
}
}
@@ -103,9 +98,10 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
// ! unfortunately it seems there is no way on Linux to get a failure notification for calling an invalid command line asynchronously !
//by default wxExecute uses a zero sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list
- //=> use wxEXEC_NODISABLE and roll our own window disabler! (see comment in app.cpp: void *wxGUIAppTraits::BeforeChildWaitLoop())
+ //=> use wxEXEC_NODISABLE and roll our own window disabler! (see comment in app.cpp: void *wxGUIAppTraits::BeforeChildWaitLoop())
wxWindowDisabler dummy; //disables all top level windows
wxExecute(command, wxEXEC_ASYNC | wxEXEC_NODISABLE);
+ wxLog::FlushActive(); //show wxWidgets error messages (if any)
}
#endif
}
diff --git a/wx+/string_conv.h b/wx+/string_conv.h
index 65764b1f..b23f6947 100644
--- a/wx+/string_conv.h
+++ b/wx+/string_conv.h
@@ -16,6 +16,14 @@ namespace zen
//conversion between Zstring and wxString
inline wxString toWx(const Zstring& str) { return utf8CvrtTo<wxString>(str); }
inline Zstring toZ(const wxString& str) { return utf8CvrtTo<Zstring>(str); }
+
+inline std::vector<Zstring> toZ(const std::vector<wxString>& strList)
+{
+ std::vector<Zstring> tmp;
+ std::transform(strList.begin(), strList.end(), std::back_inserter(tmp), [](const wxString& str) { return toZ(str); });
+ return tmp;
+}
+
}
#endif // STRINGCONV_H_INCLUDED
diff --git a/wx+/toggle_button.h b/wx+/toggle_button.h
index cce7f5b2..74f90974 100644
--- a/wx+/toggle_button.h
+++ b/wx+/toggle_button.h
@@ -27,9 +27,9 @@ public:
}
void init(const wxBitmap& activeBmp,
- const wxString& activeTooltip,
const wxBitmap& inactiveBmp,
- const wxString& inactiveTooltip);
+ const wxString& activeTooltip,
+ const wxString& inactiveTooltip = wxString());
void setActive(bool value);
bool isActive() const { return active; }
@@ -60,14 +60,14 @@ private:
//######################## implementation ########################
inline
void ToggleButton::init(const wxBitmap& activeBmp,
- const wxString& activeTooltip,
const wxBitmap& inactiveBmp,
+ const wxString& activeTooltip,
const wxString& inactiveTooltip)
{
m_activeBmp = activeBmp;
m_activeTooltip = activeTooltip;
m_inactiveBmp = inactiveBmp;
- m_inactiveTooltip = inactiveTooltip;
+ m_inactiveTooltip = inactiveTooltip.empty() ? activeTooltip : inactiveTooltip;
//load resources
setActive(active);
diff --git a/wxWidgets-Fix/apply-patches.cmd b/wxWidgets-Fix/apply-patches.cmd
deleted file mode 100644
index e8f6891c..00000000
--- a/wxWidgets-Fix/apply-patches.cmd
+++ /dev/null
@@ -1,5 +0,0 @@
-@if [%1]==[] echo Please pass wxWidgets installation directory as %%1 parameter, e.g.: C:\Programme\C++\wxWidgets && pause && exit
-
-::Segoe UI font with Vista
-patch "%1\src\msw\settings.cpp" settings.cpp.patch
-pause \ No newline at end of file
diff --git a/wxWidgets-Fix/settings.cpp.patch b/wxWidgets-Fix/settings.cpp.patch
deleted file mode 100644
index 3c48d052..00000000
--- a/wxWidgets-Fix/settings.cpp.patch
+++ /dev/null
@@ -1,60 +0,0 @@
---- settings.cpp.old 2011-03-22 10:36:54.000000000 +0100
-+++ settings.cpp 2012-01-23 00:26:06.916105800 +0100
-@@ -40,6 +40,8 @@
- #endif
-
- #include "wx/fontutil.h"
-+//#include <vssym32.h>
-+#include <Uxtheme.h>
-
- // ----------------------------------------------------------------------------
- // private classes
-@@ -261,6 +263,48 @@
- return font;
- }
-
-+#ifndef TMT_MSGBOXFONT
-+#define TMT_MSGBOXFONT 805 //why is this constant missing from Uxtheme.h???
-+#endif
-+
-+typedef HTHEME (WINAPI* OpenThemeDataFun )(HWND hwnd, LPCWSTR pszClassList);
-+typedef HRESULT (WINAPI* CloseThemeDataFun )(HTHEME hTheme);
-+typedef HRESULT (WINAPI* GetThemeSysFontFun)(HTHEME hTheme, int iFontID, LOGFONTW* plf);
-+
-+struct InitFont //(try to) initialize default font, before wxWidgets gets chance to screw up
-+{
-+ InitFont()
-+ {
-+ //Windows 2000 doesn't ship with this dll so we need to link it dynamically
-+ if (HMODULE lib = ::LoadLibrary(L"UxTheme.dll"))
-+ {
-+ OpenThemeDataFun OpenThemeData = reinterpret_cast<OpenThemeDataFun >(::GetProcAddress(lib, "OpenThemeData"));
-+ CloseThemeDataFun CloseThemeData = reinterpret_cast<CloseThemeDataFun >(::GetProcAddress(lib, "CloseThemeData"));
-+ GetThemeSysFontFun GetThemeSysFont = reinterpret_cast<GetThemeSysFontFun>(::GetProcAddress(lib, "GetThemeSysFont"));
-+
-+ HTHEME theme = (*OpenThemeData)(NULL, //__in HWND hwnd,
-+ L"WINDOW"); //__in LPCWSTR pszClassList
-+
-+ LOGFONT lfont = {};
-+ if ((*GetThemeSysFont)(theme, //__in HTHEME hTheme,
-+ TMT_MSGBOXFONT, //__in int iFontID,
-+ &lfont) == S_OK) // __out LOGFONTW *plf
-+ {
-+ wxNativeFontInfo native;
-+ native.lf = lfont;
-+ delete gs_fontDefault;
-+ gs_fontDefault = wxFontBase::New(native);
-+ }
-+
-+ if (theme != NULL)
-+ (*CloseThemeData)(theme);
-+
-+ ::FreeLibrary(lib);
-+ }
-+ }
-+} dummy;
-+
-+
- wxFont wxSystemSettingsNative::GetFont(wxSystemFont index)
- {
- #ifdef __WXWINCE__
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index 46eb956c..ad385668 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -295,7 +295,7 @@ void FileSearcher::readDirImpl(FileInformation& output) //throw FileError
QueryPolicy::extractFileId(dirInfo, output);
output.creationTime = toFileTime(dirInfo.CreationTime);
- output.lastWriteTime = toFileTime(dirInfo.LastWriteTime);
+ output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); //the similar field "ChangeTime" refers to changes to metadata in addition to write accesses
output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart;
output.fileAttributes = dirInfo.FileAttributes;
output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes!
diff --git a/zen/FindFilePlus/find_file_plus.h b/zen/FindFilePlus/find_file_plus.h
index 7306c32e..7d03d98b 100644
--- a/zen/FindFilePlus/find_file_plus.h
+++ b/zen/FindFilePlus/find_file_plus.h
@@ -45,7 +45,7 @@ typedef FileSearcher* FindHandle;
DLL_FUNCTION_DECLARATION
FindHandle openDir(const wchar_t* dirname); //returns nullptr on error, call ::GetLastError()
-//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile()
+//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as you would do for ::FindFirstFile()
DLL_FUNCTION_DECLARATION
bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES in this case
@@ -53,7 +53,7 @@ bool readDir(FindHandle hnd, FileInformation& output); //returns false on error
warning:; this may also return file system implementation dependent error codes like ERROR_NOT_SUPPORTED, ERROR_INVALID_LEVEL,
ect. if "FileIdBothDirectoryInformation" is not supported! We need a fallback:
- sometimes it's *not* sufficient to use fallback for NtQueryDirectoryFile() alone, we need to reset "hDir", since it may be f$ck$d $p by some poor file system layer implementation:
+ sometimes it's *not* sufficient to use fallback for NtQueryDirectoryFile() alone, we need to reset "hDir", since it may be fucked up by some poor file system layer implementation:
- Samba before v3.0.22 (Mar 30, 2006) seems to have a bug which sucessfully returns 128 elements via NtQueryDirectoryFile() and FileIdBothDirectoryInformation,
then fails with STATUS_INVALID_LEVEL. Fallback to FileBothDirectoryInformation will return STATUS_NO_MORE_FILES, even if there *are* more files
- NtQueryDirectoryFile() may *not* respect "restartScan" for some weird Win2000 file system drivers, so we cannot rely on this as a replacement for a "hDir" reset
@@ -69,17 +69,17 @@ void closeDir(FindHandle hnd);
/*----------
|typedefs|
----------*/
-typedef FindHandle (*OpenDirFunc )(const wchar_t* dirname);
-typedef bool (*ReadDirFunc )(FindHandle hnd, FileInformation& dirInfo);
-typedef void (*CloseDirFunc)(FindHandle hnd);
+typedef FindHandle (*FunType_openDir )(const wchar_t* dirname);
+typedef bool (*FunType_readDir )(FindHandle hnd, FileInformation& dirInfo);
+typedef void (*FunType_closeDir)(FindHandle hnd);
/*--------------
|symbol names|
--------------*/
//const pointers ensure internal linkage
-const char openDirFuncName [] = "openDir";
-const char readDirFuncName [] = "readDir";
-const char closeDirFuncName[] = "closeDir";
+const char funName_openDir [] = "openDir";
+const char funName_readDir [] = "readDir";
+const char funName_closeDir[] = "closeDir";
/*---------------
|library names|
diff --git a/lib/IFileOperation/FileOperation_Vista.vcxproj b/zen/IFileOperation/FileOperation_Vista.vcxproj
index 3d454a0b..a387dcb5 100644
--- a/lib/IFileOperation/FileOperation_Vista.vcxproj
+++ b/zen/IFileOperation/FileOperation_Vista.vcxproj
@@ -98,7 +98,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -110,6 +110,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -131,7 +132,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -143,6 +144,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -162,7 +164,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -176,6 +178,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -198,7 +201,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -212,6 +215,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
diff --git a/lib/IFileOperation/dll_main.cpp b/zen/IFileOperation/dll_main.cpp
index 46c65311..46c65311 100644
--- a/lib/IFileOperation/dll_main.cpp
+++ b/zen/IFileOperation/dll_main.cpp
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
new file mode 100644
index 00000000..7c75a8e8
--- /dev/null
+++ b/zen/IFileOperation/file_op.cpp
@@ -0,0 +1,349 @@
+// **************************************************************************
+// * 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 "file_op.h"
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#define WIN32_LEAN_AND_MEAN
+#include <zen/com_ptr.h>
+#include <zen/com_error.h>
+#include <zen/scope_guard.h>
+
+#include <boost/thread/tss.hpp>
+
+#include <RestartManager.h>
+#pragma comment(lib, "Rstrtmgr.lib")
+
+#define STRICT_TYPED_ITEMIDS //better type safety for IDLists
+#include <Shlobj.h>
+#include <shobjidl.h>
+#include <shellapi.h> //shell constants such as FO_* values
+
+using namespace zen;
+
+
+namespace
+{
+void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
+ size_t fileNo) //size of fileNames array
+{
+ ComPtr<IFileOperation> fileOp;
+ ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(fileOp.init())));
+
+ // Set the operation flags. Turn off all UI
+ // from being shown to the user during the
+ // operation. This includes error, confirmation
+ // and progress dialogs.
+ ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_ALLOWUNDO | //throw ComError
+ FOF_NOCONFIRMATION |
+ FOF_SILENT |
+ FOF_NOERRORUI |
+ FOFX_EARLYFAILURE |
+ FOF_NO_CONNECTED_ELEMENTS));
+
+ int operationCount = 0;
+
+ for (size_t i = 0; i < fileNo; ++i)
+ {
+ //create file/folder item object
+ ComPtr<IShellItem> psiFile;
+ HRESULT hr = ::SHCreateItemFromParsingName(fileNames[i],
+ nullptr,
+ IID_PPV_ARGS(psiFile.init()));
+ if (FAILED(hr))
+ {
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore
+ hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
+ continue;
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr);
+ }
+
+ ZEN_CHECK_COM(fileOp->DeleteItem(psiFile.get(), nullptr));
+
+ ++operationCount;
+ }
+
+ if (operationCount == 0) //calling PerformOperations() without anything to do would result in E_UNEXPECTED
+ return;
+
+ //perform actual operations
+ ZEN_CHECK_COM(fileOp->PerformOperations());
+
+ //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
+ BOOL pfAnyOperationsAborted = FALSE;
+ ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
+
+ if (pfAnyOperationsAborted == TRUE)
+ throw ComError(L"Operation did not complete successfully.");
+}
+
+
+void copyFile(const wchar_t* sourceFile, //throw ComError
+ const wchar_t* targetFile)
+{
+ ComPtr<IFileOperation> fileOp;
+ ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
+ nullptr,
+ CLSCTX_ALL,
+ IID_PPV_ARGS(fileOp.init())));
+
+ // Set the operation flags. Turn off all UI
+ // from being shown to the user during the
+ // operation. This includes error, confirmation
+ // and progress dialogs.
+ ZEN_CHECK_COM(fileOp->SetOperationFlags(FOF_NOCONFIRMATION | //throw ComError
+ FOF_SILENT |
+ FOFX_EARLYFAILURE |
+ FOF_NOERRORUI));
+ //create source object
+ ComPtr<IShellItem> psiSourceFile;
+ {
+ HRESULT hr = ::SHCreateItemFromParsingName(sourceFile,
+ nullptr,
+ IID_PPV_ARGS(psiSourceFile.init()));
+ if (FAILED(hr))
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr);
+ }
+
+ const size_t pos = std::wstring(targetFile).find_last_of(L'\\');
+ if (pos == std::wstring::npos)
+ throw ComError(L"Target filename does not contain a path separator.");
+
+ const std::wstring targetFolder(targetFile, pos);
+ const std::wstring targetFileNameShort = targetFile + pos + 1;
+
+ //create target folder object
+ ComPtr<IShellItem> psiTargetFolder;
+ {
+ HRESULT hr = ::SHCreateItemFromParsingName(targetFolder.c_str(),
+ nullptr,
+ IID_PPV_ARGS(psiTargetFolder.init()));
+ if (FAILED(hr))
+ throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr);
+ }
+
+ //schedule file copy operation
+ ZEN_CHECK_COM(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), nullptr));
+
+ //perform actual operations
+ ZEN_CHECK_COM(fileOp->PerformOperations());
+
+ //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors!
+ BOOL pfAnyOperationsAborted = FALSE;
+ ZEN_CHECK_COM(fileOp->GetAnyOperationsAborted(&pfAnyOperationsAborted));
+
+ if (pfAnyOperationsAborted == TRUE)
+ throw ComError(L"Operation did not complete successfully.");
+}
+
+
+void getFolderClsid(const wchar_t* dirname, CLSID& pathCLSID) //throw ComError
+{
+ ComPtr<IShellFolder> desktopFolder;
+ ZEN_CHECK_COM(::SHGetDesktopFolder(desktopFolder.init())); //throw ComError
+
+ PIDLIST_RELATIVE pidlFolder = nullptr;
+ ZEN_CHECK_COM(desktopFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
+ nullptr, // [in] IBindCtx *pbc,
+ const_cast<LPWSTR>(dirname), // [in] LPWSTR pszDisplayName,
+ nullptr, // [out] ULONG *pchEaten,
+ &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
+ nullptr)); // [in, out] ULONG *pdwAttributes
+ ZEN_ON_SCOPE_EXIT(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree
+
+ ComPtr<IPersist> persistFolder;
+ ZEN_CHECK_COM(desktopFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
+ nullptr, // [in] IBindCtx *pbc,
+ IID_PPV_ARGS(persistFolder.init()))); //throw ComError
+
+ ZEN_CHECK_COM(persistFolder->GetClassID(&pathCLSID)); //throw ComError
+}
+
+
+struct Win32Error
+{
+ Win32Error(DWORD errorCode) : errorCode_(errorCode) {}
+ DWORD errorCode_;
+};
+
+std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw Win32Error
+{
+ wchar_t sessionKey[CCH_RM_SESSION_KEY + 1] = {}; //fixes two bugs: http://blogs.msdn.com/b/oldnewthing/archive/2012/02/17/10268840.aspx
+ DWORD sessionHandle = 0;
+ DWORD rv1 = ::RmStartSession(&sessionHandle, //__out DWORD *pSessionHandle,
+ 0, //__reserved DWORD dwSessionFlags,
+ sessionKey); //__out WCHAR strSessionKey[ ]
+ if (rv1 != ERROR_SUCCESS)
+ throw Win32Error(rv1);
+ ZEN_ON_SCOPE_EXIT(::RmEndSession(sessionHandle));
+
+ DWORD rv2 = ::RmRegisterResources(sessionHandle, //__in DWORD dwSessionHandle,
+ 1, //__in UINT nFiles,
+ &filename, //__in_opt LPCWSTR rgsFilenames[ ],
+ 0, //__in UINT nApplications,
+ nullptr, //__in_opt RM_UNIQUE_PROCESS rgApplications[ ],
+ 0, //__in UINT nServices,
+ nullptr); //__in_opt LPCWSTR rgsServiceNames[ ]
+ if (rv2 != ERROR_SUCCESS)
+ throw Win32Error(rv2);
+
+ UINT procInfoSize = 0;
+ UINT procInfoSizeNeeded = 0;
+ DWORD rebootReasons = 0;
+ ::RmGetList(sessionHandle, &procInfoSizeNeeded, &procInfoSize, nullptr, &rebootReasons); //get procInfoSizeNeeded
+ //fails with "access denied" for C:\pagefile.sys!
+
+ if (procInfoSizeNeeded == 0)
+ return std::vector<std::wstring>();
+
+ procInfoSize = procInfoSizeNeeded;
+ std::vector<RM_PROCESS_INFO> procInfo(procInfoSize);
+
+ DWORD rv3 = ::RmGetList(sessionHandle, //__in DWORD dwSessionHandle,
+ &procInfoSizeNeeded, //__out UINT *pnProcInfoNeeded,
+ &procInfoSize, //__inout UINT *pnProcInfo,
+ &procInfo[0], //__inout_opt RM_PROCESS_INFO rgAffectedApps[ ],
+ &rebootReasons); //__out LPDWORD lpdwRebootReasons
+ if (rv3 != ERROR_SUCCESS)
+ throw Win32Error(rv3);
+ procInfo.resize(procInfoSize);
+
+ std::vector<std::wstring> output;
+ for (auto iter = procInfo.begin(); iter != procInfo.end(); ++iter)
+ {
+ std::wstring processName = iter->strAppName;
+
+ //try to get process path
+ HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, //__in DWORD dwDesiredAccess,
+ false, //__in BOOL bInheritHandle,
+ iter->Process.dwProcessId); //__in DWORD dwProcessId
+ if (hProcess)
+ {
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hProcess));
+
+ FILETIME creationTime = {};
+ FILETIME exitTime = {};
+ FILETIME kernelTime = {};
+ FILETIME userTime = {};
+ if (::GetProcessTimes(hProcess, //__in HANDLE hProcess,
+ &creationTime, //__out LPFILETIME lpCreationTime,
+ &exitTime, //__out LPFILETIME lpExitTime,
+ &kernelTime, //__out LPFILETIME lpKernelTime,
+ &userTime)) //__out LPFILETIME lpUserTime
+ if (::CompareFileTime(&iter->Process.ProcessStartTime, &creationTime) == 0)
+ {
+ DWORD bufferSize = MAX_PATH;
+ std::vector<wchar_t> buffer(bufferSize);
+ if (::QueryFullProcessImageName(hProcess, //__in HANDLE hProcess,
+ 0, //__in DWORD dwFlags,
+ &buffer[0], //__out LPTSTR lpExeName,
+ &bufferSize)) //__inout PDWORD lpdwSize
+ if (bufferSize < buffer.size())
+ processName += std::wstring(L" - ") + L"\"" + &buffer[0] + L"\"";
+ }
+ }
+ output.push_back(processName);
+ }
+ return output;
+}
+
+
+boost::thread_specific_ptr<std::wstring> lastErrorMessage; //use "thread_local" in C++11
+}
+
+
+bool fileop::moveToRecycleBin(const wchar_t* fileNames[], size_t fileNo) //size of fileNames array
+{
+ try
+ {
+ ::moveToRecycleBin(fileNames, fileNo); //throw ComError
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+bool fileop::copyFile(const wchar_t* sourceFile,
+ const wchar_t* targetFile)
+{
+ try
+ {
+ ::copyFile(sourceFile, targetFile); //throw ComError
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+bool fileop::checkRecycler(const wchar_t* dirname, bool& isRecycler)
+{
+ try
+ {
+ CLSID clsid = {};
+ getFolderClsid(dirname, clsid); //throw ComError
+ isRecycler = ::IsEqualCLSID(clsid, CLSID_RecycleBin) == TRUE; //silence perf warning
+ return true;
+ }
+ catch (const ComError& e)
+ {
+ lastErrorMessage.reset(new std::wstring(e.toString()));
+ return false;
+ }
+}
+
+
+const wchar_t* fileop::getLastError()
+{
+ return !lastErrorMessage.get() ? L"" : lastErrorMessage->c_str();
+}
+
+
+bool fileop::getLockingProcesses(const wchar_t* filename, const wchar_t*& procList)
+{
+ try
+ {
+ std::vector<std::wstring> result = ::getLockingProcesses(filename); //throw Win32Error
+
+ std::wstring buffer;
+ for (auto iter = result.begin(); iter != result.end(); ++iter)
+ {
+ buffer += *iter;
+ buffer += L'\n';
+ }
+ if (!buffer.empty())
+ buffer.resize(buffer.size() - 1); //remove last line break
+
+ auto tmp = new wchar_t [buffer.size() + 1]; //bad_alloc ?
+ ::wmemcpy(tmp, buffer.c_str(), buffer.size() + 1); //include 0-termination
+ procList = tmp; //ownership passed
+
+ return true;
+ }
+ catch (const Win32Error& e)
+ {
+ lastErrorMessage.reset(new std::wstring(formatWin32Msg(e.errorCode_)));
+ return false;
+ }
+}
+
+
+void fileop::freeString(const wchar_t* str)
+{
+ delete [] str;
+}
diff --git a/lib/IFileOperation/file_op.h b/zen/IFileOperation/file_op.h
index 530226d3..fb157301 100644
--- a/lib/IFileOperation/file_op.h
+++ b/zen/IFileOperation/file_op.h
@@ -23,6 +23,7 @@ namespace fileop
--------------*/
//COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize
+//minimum OS: Windows Vista or later
FILE_OP_DLL_API
bool moveToRecycleBin(const wchar_t* fileNames[],
@@ -32,24 +33,39 @@ FILE_OP_DLL_API
bool copyFile(const wchar_t* sourceFile,
const wchar_t* targetFile);
-//if any of the functions above returns 'false', this message returns last error
FILE_OP_DLL_API
-void getLastError(wchar_t* errorMessage, size_t errorBufferLen);
+bool checkRecycler(const wchar_t* dirname, bool& isRecycler); //returns false on error
+
+FILE_OP_DLL_API
+bool getLockingProcesses(const wchar_t* filename, const wchar_t*& procList); //get list of processes as single string, call freeString(procList) after use!
+
+FILE_OP_DLL_API
+void freeString(const wchar_t* str);
+
+//get last error message if any of the functions above fail
+FILE_OP_DLL_API
+const wchar_t* getLastError(); //no nullptr check required!
/*----------
|typedefs|
----------*/
-typedef bool (*MoveToRecycleBinFct)(const wchar_t* fileNames[], size_t fileNo);
-typedef bool (*CopyFileFct)(const wchar_t* sourceFile, const wchar_t* targetFile);
-typedef void (*GetLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen);
+typedef bool (*FunType_moveToRecycleBin)(const wchar_t* fileNames[], size_t fileNo);
+typedef bool (*FunType_copyFile)(const wchar_t* sourceFile, const wchar_t* targetFile);
+typedef bool (*FunType_checkRecycler)(const wchar_t* dirname, bool& isRecycler);
+typedef bool (*FunType_getLockingProcesses)(const wchar_t* filename, const wchar_t*& procList);
+typedef void (*FunType_freeString)(const wchar_t* str);
+typedef const wchar_t* (*FunType_getLastError)();
/*--------------
|symbol names|
--------------*/
//(use const pointers to ensure internal linkage)
-const char moveToRecycleBinFctName[] = "moveToRecycleBin";
-const char copyFileFctName[] = "copyFile";
-const char getLastErrorFctName[] = "getLastError";
+const char funName_moveToRecycleBin [] = "moveToRecycleBin";
+const char funName_copyFile [] = "copyFile";
+const char funName_checkRecycler [] = "checkRecycler";
+const char funName_getLockingProcesses[] = "getLockingProcesses";
+const char funName_freeString [] = "freeString";
+const char funName_getLastError [] = "getLastError";
/*---------------
|library names|
@@ -57,6 +73,4 @@ const char getLastErrorFctName[] = "getLastError";
inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FileOperation_x64.dll" : L"FileOperation_Win32.dll"; }
}
-
-
#endif //RECYCLER_DLL_H
diff --git a/zen/com_error.h b/zen/com_error.h
index c67c4193..d891fa13 100644
--- a/zen/com_error.h
+++ b/zen/com_error.h
@@ -212,17 +212,16 @@ std::wstring generateErrorMsg(const std::wstring& input, HRESULT hr)
{
std::wstring output(input);
output += L"\n";
- output += L"HRESULT: " + numberToHexString(hr) + L",\n";
//don't use _com_error(hr).ErrorMessage(): internally this is nothing more than a call to ::FormatMessage()
std::wstring win32Msg = formatWin32Msg(hr);
if (!win32Msg.empty()) //empty string on error
- output += win32Msg;
+ output += win32Msg + L"\n" + L"HRESULT: " + numberToHexString(hr);
else
- {
- output += L"Facility: " + formatFacility(hr) + L",\n";
- output += L"Win32 Error: " + formatWin32Msg(HRESULT_CODE(hr)); //interpret hr as a Win32 code; this is often useful...
- }
+ output += L"HRESULT: " + numberToHexString(hr) + L", " + L"Facility: " + formatFacility(hr);
+ //don't bluntly interpret as Win32 error code HRESULT_CODE(hr), too often misleading!
+ //http://blogs.msdn.com/b/oldnewthing/archive/2006/11/03/942851.aspx
+
return output;
}
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index ed07a1e4..19c56d5a 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -50,7 +50,7 @@ public:
const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR));
//skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately!
- [&]()
+ [&]
{
if (notifyInfo.Action == FILE_ACTION_RENAMED_OLD_NAME) //reporting FILE_ACTION_RENAMED_NEW_NAME should suffice
return;
@@ -125,12 +125,9 @@ public:
ReadChangesAsync(const Zstring& directory, //make sure to not leak in thread-unsafe types!
const std::shared_ptr<SharedData>& shared) :
shared_(shared),
- dirname(directory),
+ dirnamePf(appendSeparator(directory)),
hDir(INVALID_HANDLE_VALUE)
{
- if (!endsWith(dirname, FILE_NAME_SEPARATOR))
- dirname += FILE_NAME_SEPARATOR;
-
//these two privileges are required by ::CreateFile FILE_FLAG_BACKUP_SEMANTICS according to
//http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx
try
@@ -140,7 +137,7 @@ public:
}
catch (const FileError&) {}
- hDir = ::CreateFile(applyLongPathPrefix(dirname.c_str()).c_str(),
+ hDir = ::CreateFile(applyLongPathPrefix(dirnamePf.c_str()).c_str(),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
@@ -149,8 +146,9 @@ public:
nullptr);
if (hDir == INVALID_HANDLE_VALUE)
{
- const std::wstring errorMsg = _("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" L"\n\n" + zen::getLastErrorFormatted();
- if (errorCodeForNotExisting(::GetLastError()))
+ const DWORD lastError = ::GetLastError();
+ const std::wstring errorMsg = replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted(lastError);
+ if (errorCodeForNotExisting(lastError))
throw ErrorNotExisting(errorMsg);
throw FileError(errorMsg);
}
@@ -181,14 +179,15 @@ public:
false, //__in BOOL bInitialState,
nullptr); //__in_opt LPCTSTR lpName
if (overlapped.hEvent == nullptr)
- return shared_->reportError(_("Error when monitoring directories.") + L" (CreateEvent)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)) + L" (CreateEvent)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+
ZEN_ON_SCOPE_EXIT(::CloseHandle(overlapped.hEvent));
//asynchronous variant: runs on this thread's APC queue!
- if (!::ReadDirectoryChangesW(hDir, // __in HANDLE hDirectory,
- &buffer[0], // __out LPVOID lpBuffer,
- static_cast<DWORD>(buffer.size()), // __in DWORD nBufferLength,
- true, // __in BOOL bWatchSubtree,
+ if (!::ReadDirectoryChangesW(hDir, // __in HANDLE hDirectory,
+ &buffer[0], // __out LPVOID lpBuffer,
+ static_cast<DWORD>(buffer.size()), // __in DWORD nBufferLength,
+ true, // __in BOOL bWatchSubtree,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE |
@@ -196,7 +195,7 @@ public:
nullptr, // __out_opt LPDWORD lpBytesReturned,
&overlapped, // __inout_opt LPOVERLAPPED lpOverlapped,
nullptr)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
- return shared_->reportError(_("Error when monitoring directories.") + L" (ReadDirectoryChangesW)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)) + L" (ReadDirectoryChangesW)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
//async I/O is a resource that needs to be guarded since it will write to local variable "buffer"!
zen::ScopeGuard guardAio = zen::makeGuard([&]
@@ -217,7 +216,7 @@ public:
false)) //__in BOOL bWait
{
if (::GetLastError() != ERROR_IO_INCOMPLETE)
- return shared_->reportError(_("Error when monitoring directories.") + L" (GetOverlappedResult)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)) + L" (GetOverlappedResult)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
//execute asynchronous procedure calls (APC) queued on this thread
::SleepEx(50, // __in DWORD dwMilliseconds,
@@ -227,7 +226,7 @@ public:
}
guardAio.dismiss();
- shared_->addChanges(&buffer[0], bytesWritten, dirname); //throw ()
+ shared_->addChanges(&buffer[0], bytesWritten, dirnamePf); //throw ()
}
}
catch (boost::thread_interrupted&)
@@ -236,21 +235,24 @@ public:
}
}
- ReadChangesAsync(ReadChangesAsync && other) :
+ ReadChangesAsync(ReadChangesAsync&& other) :
hDir(INVALID_HANDLE_VALUE)
{
- shared_ = std::move(other.shared_);
- dirname = std::move(other.dirname);
+ shared_ = std::move(other.shared_);
+ dirnamePf = std::move(other.dirnamePf);
std::swap(hDir, other.hDir);
}
HANDLE getDirHandle() const { return hDir; } //for reading/monitoring purposes only, don't abuse (e.g. close handle)!
private:
+ ReadChangesAsync(const ReadChangesAsync&);
+ ReadChangesAsync& operator=(const ReadChangesAsync&);
+
//shared between main and worker:
std::shared_ptr<SharedData> shared_;
//worker thread only:
- Zstring dirname; //thread safe!
+ Zstring dirnamePf; //thread safe!
HANDLE hDir;
};
@@ -347,8 +349,9 @@ std::vector<Zstring> DirWatcher::getChanges(const std::function<void()>& process
#elif defined FFS_LINUX
struct DirWatcher::Pimpl
{
+ Zstring dirname;
int notifDescr;
- std::map<int, Zstring> watchDescrs; //watch descriptor and corresponding directory name (postfixed with separator!)
+ std::map<int, Zstring> watchDescrs; //watch descriptor and corresponding (sub-)directory name (postfixed with separator!)
};
@@ -394,11 +397,12 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
zen::traverseFolder(dirname, false, *traverser); //don't traverse into symlinks (analog to windows build)
//init
+ pimpl_->dirname = directory;
pimpl_->notifDescr = ::inotify_init();
if (pimpl_->notifDescr == -1)
- throw FileError(_("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)) + L"\n\n" + getLastErrorFormatted());
- zen::ScopeGuard guardDescr = zen::makeGuard([&]() { ::close(pimpl_->notifDescr); });
+ zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->notifDescr); });
//set non-blocking mode
bool initSuccess = false;
@@ -407,7 +411,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1;
if (!initSuccess)
- throw FileError(_("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)) + L"\n\n" + getLastErrorFormatted());
//add watches
std::for_each(fullDirList.begin(), fullDirList.end(),
@@ -425,15 +429,13 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
IN_MOVE_SELF);
if (wd == -1)
{
- std::wstring errorMsg = _("Could not initialize directory monitoring:") + L"\n\"" + subdir + L"\"" + L"\n\n" + getLastErrorFormatted();
- if (errno == ENOENT)
+ const std::wstring errorMsg = replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(subdir)) + L"\n\n" + getLastErrorFormatted();
+ if (errorCodeForNotExisting(errno))
throw ErrorNotExisting(errorMsg);
throw FileError(errorMsg);
}
- if (!endsWith(subdir, FILE_NAME_SEPARATOR))
- subdir += FILE_NAME_SEPARATOR;
- pimpl_->watchDescrs.insert(std::make_pair(wd, subdir));
+ pimpl_->watchDescrs.insert(std::make_pair(wd, appendSeparator(subdir)));
});
guardDescr.dismiss();
@@ -448,9 +450,8 @@ DirWatcher::~DirWatcher()
std::vector<Zstring> DirWatcher::getChanges(const std::function<void()>&) //throw FileError
{
- std::vector<char> buffer(1024 * (sizeof(struct inotify_event) + 16));
-
//non-blocking call, see O_NONBLOCK
+ std::vector<char> buffer(1024 * (sizeof(struct inotify_event) + 16));
ssize_t bytesRead = ::read(pimpl_->notifDescr, &buffer[0], buffer.size());
if (bytesRead == -1)
@@ -459,7 +460,7 @@ std::vector<Zstring> DirWatcher::getChanges(const std::function<void()>&) //thro
errno == EAGAIN) //Non-blocking I/O has been selected using O_NONBLOCK and no data was immediately available for reading
return std::vector<Zstring>();
- throw FileError(_("Error when monitoring directories.") + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->dirname)) + L"\n\n" + getLastErrorFormatted());
}
std::set<Zstring> tmp; //get rid of duplicate entries (actually occur!)
diff --git a/zen/dst_hack.cpp b/zen/dst_hack.cpp
index 3ecfd8e9..9457b966 100644
--- a/zen/dst_hack.cpp
+++ b/zen/dst_hack.cpp
@@ -21,13 +21,9 @@ Zstring getVolumeName(const Zstring& filename)
// fsName, //__out LPTSTR lpszVolumePathName,
// BUFFER_SIZE)) //__in DWORD cchBufferLength
// ...
- // Zstring volumePath = fsName;
- // if (!volumePath.EndsWith(FILE_NAME_SEPARATOR)) //a trailing backslash is required
- // volumePath += FILE_NAME_SEPARATOR;
+ // Zstring volumePath = appendSeparator(fsName);
- Zstring nameFmt = removeLongPathPrefix(filename); //throw()
- if (!endsWith(nameFmt, FILE_NAME_SEPARATOR))
- nameFmt += FILE_NAME_SEPARATOR; //GetVolumeInformation expects trailing backslash
+ const Zstring nameFmt = appendSeparator(removeLongPathPrefix(filename)); //throw()
if (startsWith(nameFmt, Zstr("\\\\"))) //UNC path: "\\ComputerName\SharedFolder\"
{
@@ -82,8 +78,10 @@ bool dst::isFatDrive(const Zstring& fileName) //throw()
}
+/*
bool dst::isFatDrive(HANDLE hFile) //throw()
{
+Requires Windows Vista!
//dynamically load windows API function
typedef BOOL (WINAPI* GetVolumeInformationByHandleWFunc)(HANDLE hFile,
LPWSTR lpVolumeNameBuffer,
@@ -120,6 +118,7 @@ bool dst::isFatDrive(HANDLE hFile) //throw()
return fsName == Zstring(L"FAT") ||
fsName == Zstring(L"FAT32");
}
+*/
namespace
@@ -159,7 +158,7 @@ Int64 toInt64(const FILETIME& fileTime)
inline
-FILETIME utcToLocal(const FILETIME& utcTime) //throw (std::runtime_error)
+FILETIME utcToLocal(const FILETIME& utcTime) //throw std::runtime_error
{
//treat binary local time representation (which is invariant under DST time zone shift) as logical UTC:
FILETIME localTime = {};
@@ -177,7 +176,7 @@ FILETIME utcToLocal(const FILETIME& utcTime) //throw (std::runtime_error)
inline
-FILETIME localToUtc(const FILETIME& localTime) //throw (std::runtime_error)
+FILETIME localToUtc(const FILETIME& localTime) //throw std::runtime_error
{
//treat binary local time representation (which is invariant under DST time zone shift) as logical UTC:
FILETIME utcTime = {};
@@ -330,7 +329,7 @@ bool dst::fatHasUtcEncoded(const RawTime& rawTime) //"createTimeRaw" as retrieve
}
-dst::RawTime dst::fatEncodeUtcTime(const FILETIME& writeTimeRealUtc) //throw (std::runtime_error)
+dst::RawTime dst::fatEncodeUtcTime(const FILETIME& writeTimeRealUtc) //throw std::runtime_error
{
const FILETIME fatWriteTimeUtc = roundToFatWriteTime(writeTimeRealUtc); //writeTimeRealUtc may have incompatible precision (NTFS)
diff --git a/zen/dst_hack.h b/zen/dst_hack.h
index 07d08dc5..600107bb 100644
--- a/zen/dst_hack.h
+++ b/zen/dst_hack.h
@@ -19,8 +19,6 @@ Solve DST +-1h and time zone shift issues on FAT drives
*/
bool isFatDrive(const Zstring& fileName); //throw ()
-bool isFatDrive(HANDLE hFile); //throw() -> call ONLY if vistaOrLater() == true!
-bool vistaOrLater();
//all subsequent functions may throw the std::runtime_error exception!
@@ -31,10 +29,10 @@ struct RawTime //time as retrieved by ::FindFirstFile() and ::GetFileAttributesE
FILETIME writeTimeRaw;
};
//save UTC time resistant against DST/time zone shifts
-bool fatHasUtcEncoded(const RawTime& rawTime); //as retrieved by ::FindFirstFile() and ::GetFileAttributesEx(); throw (std::runtime_error)
+bool fatHasUtcEncoded(const RawTime& rawTime); //throw std::runtime_error; as retrieved by ::FindFirstFile() and ::GetFileAttributesEx()
-RawTime fatEncodeUtcTime(const FILETIME& writeTimeRealUtc); //throw (std::runtime_error)
-FILETIME fatDecodeUtcTime(const RawTime& rawTime); //return last write time in real UTC; throw (std::runtime_error)
+RawTime fatEncodeUtcTime(const FILETIME& writeTimeRealUtc); //throw std::runtime_error
+FILETIME fatDecodeUtcTime(const RawTime& rawTime); //throw std::runtime_error; return last write time in real UTC
}
#endif // DST_HACK_H_INCLUDED
diff --git a/zen/file_error.h b/zen/file_error.h
index 853267d4..4565d0b7 100644
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -38,9 +38,22 @@ DEFINE_NEW_FILE_ERROR(ErrorFileLocked);
//----------- facilitate usage of std::wstring for error messages --------------------
//allow implicit UTF8 conversion: since std::wstring models a GUI string, convenience is more important than performance
-inline std::wstring operator+(const std::wstring& lhs, const Zstring& rhs) { return std::wstring(lhs) += zen::utf8CvrtTo<std::wstring>(rhs); }
+inline
+std::wstring operator+(const std::wstring& lhs, const Zstring& rhs) { return std::wstring(lhs) += utf8CvrtTo<std::wstring>(rhs); }
//we musn't put our overloads in namespace std, but namespace zen (+ using directive) is sufficient
+
+
+inline
+std::wstring fmtFileName(const Zstring& filename)
+{
+ std::wstring output;
+ output.reserve(filename.size() + 2);
+ output += L'\"';
+ output += utf8CvrtTo<std::wstring>(filename);
+ output += L'\"';
+ return output;
+}
}
#endif // FILEERROR_H_INCLUDED
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index a81b3a80..864fd61f 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -14,7 +14,7 @@
#include "file_io.h"
#include "assert_static.h"
#include <boost/thread/tss.hpp>
-#include <boost/thread/once.hpp>
+//#include <boost/thread/once.hpp>
#include "file_id_def.h"
#ifdef FFS_WIN
@@ -26,12 +26,14 @@
#include "dst_hack.h"
#include "file_update_handle.h"
#include "win_ver.h"
+#include "IFileOperation/file_op.h"
#elif defined FFS_LINUX
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include <sys/time.h>
+#include <sys/vfs.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
@@ -107,7 +109,7 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
{
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
if (searchHandle == INVALID_HANDLE_VALUE)
- throw FileError(_("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
::FindClose(searchHandle);
}
// WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {};
@@ -123,7 +125,7 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
if (!isDirectory && dst::isFatDrive(filename)) //throw()
{
const dst::RawTime rawTime(fileInfo.ftCreationTime, fileInfo.ftLastWriteTime);
- if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error)
+ if (dst::fatHasUtcEncoded(rawTime)) //throw std::runtime_error
{
fileInfo.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return last write time in real UTC, throw (std::runtime_error)
::GetSystemTimeAsFileTime(&fileInfo.ftCreationTime); //real creation time information is not available...
@@ -139,17 +141,18 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
const HANDLE hFile = ::CreateFile(applyLongPathPrefix(filename).c_str(), //open handle to target of symbolic link
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
if (hFile == INVALID_HANDLE_VALUE)
- throw FileError(_("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
- throw FileError(_("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
attr.fileSize = UInt64(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh);
attr.modificationTime = toTimeT(fileInfoHnd.ftLastWriteTime);
@@ -162,7 +165,7 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
:: stat(filename.c_str(), &fileInfo) :
::lstat(filename.c_str(), &fileInfo);
if (rv != 0) //follow symbolic links
- throw FileError(_("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
attr.fileSize = UInt64(fileInfo.st_size);
attr.modificationTime = fileInfo.st_mtime;
@@ -187,11 +190,54 @@ Int64 zen::getFileTime(const Zstring& filename, ProcSymlink procSl) //throw File
}
-namespace
+UInt64 zen::getFreeDiskSpace(const Zstring& path) //throw FileError
{
+#ifdef FFS_WIN
+ ULARGE_INTEGER bytesFree = {};
+ if (!::GetDiskFreeSpaceEx(appendSeparator(path).c_str(), //__in_opt LPCTSTR lpDirectoryName, -> "UNC name [...] must include a trailing backslash, for example, "\\MyServer\MyShare\"
+ &bytesFree, //__out_opt PULARGE_INTEGER lpFreeBytesAvailable,
+ nullptr, //__out_opt PULARGE_INTEGER lpTotalNumberOfBytes,
+ nullptr)) //__out_opt PULARGE_INTEGER lpTotalNumberOfFreeBytes
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)) + L"\n\n" + getLastErrorFormatted());
+
+ return UInt64(bytesFree.LowPart, bytesFree.HighPart);
+
+#elif defined FFS_LINUX
+ struct statfs info = {};
+ if (::statfs(path.c_str(), &info) != 0)
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)) + L"\n\n" + getLastErrorFormatted());
+
+ return UInt64(info.f_bsize) * info.f_bavail;
+#endif
+}
+namespace
+{
#ifdef FFS_WIN
+//(try to) enhance error messages by showing which processed lock the file
+Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string if none found or error occurred
+{
+ if (vistaOrLater())
+ {
+ using namespace fileop;
+ const DllFun<FunType_getLockingProcesses> getLockingProcesses(getDllName(), funName_getLockingProcesses);
+ const DllFun<FunType_freeString> freeString (getDllName(), funName_freeString);
+
+ if (getLockingProcesses && freeString)
+ {
+ const wchar_t* procList = nullptr;
+ if (getLockingProcesses(filename.c_str(), procList))
+ {
+ ZEN_ON_SCOPE_EXIT(freeString(procList));
+ return procList;
+ }
+ }
+ }
+ return Zstring();
+}
+
+
DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error!
{
//note: this even works for network shares: \\share\dirname
@@ -205,9 +251,7 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error!
BUFFER_SIZE)) //__in DWORD cchBufferLength
return 0;
- Zstring volumePath = &buffer[0];
- if (!endsWith(volumePath, FILE_NAME_SEPARATOR))
- volumePath += FILE_NAME_SEPARATOR;
+ Zstring volumePath = appendSeparator(&buffer[0]);
DWORD volumeSerial = 0;
if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
@@ -257,7 +301,7 @@ zen::ResponseSame zen::onSameVolume(const Zstring& folderLeft, const Zstring& fo
}
-bool zen::removeFile(const Zstring& filename) //throw FileError;
+bool zen::removeFile(const Zstring& filename) //throw FileError
{
#ifdef FFS_WIN
const Zstring& filenameFmt = applyLongPathPrefix(filename);
@@ -269,8 +313,11 @@ bool zen::removeFile(const Zstring& filename) //throw FileError;
ErrorCode lastError = getLastError();
if (errorCodeForNotExisting(lastError)) //no error situation if file is not existing! manual deletion relies on it!
return false;
+
+ const std::wstring shortMsg = replaceCpy(_("Cannot delete file %x."), L"%x", fmtFileName(filename));
+
#ifdef FFS_WIN
- else if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
+ if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
{
::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL); //(try to) normalize file attributes
@@ -278,12 +325,20 @@ bool zen::removeFile(const Zstring& filename) //throw FileError;
return true;
lastError = ::GetLastError();
}
+
+ if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message!
+ lastError == ERROR_LOCK_VIOLATION)
+ {
+ const Zstring procList = getLockingProcessNames(filename); //throw()
+ if (!procList.empty())
+ throw FileError(shortMsg + L"\n\n" + _("The file is locked by another process:") + L"\n" + procList);
+ }
#endif
//after "lastError" evaluation it *may* be redundant to check existence again, but better be safe than sorry:
if (!somethingExists(filename)) //warning: changes global error code!!
return false; //neither file nor any other object (e.g. broken symlink) with that name existing
- throw FileError(_("Error deleting file:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError));
+ throw FileError(shortMsg + L"\n\n" + getLastErrorFormatted(lastError));
}
return true;
}
@@ -312,6 +367,17 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
0)) //__in DWORD dwFlags
{
DWORD lastError = ::GetLastError();
+
+ const std::wstring shortMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", fmtFileName(oldName)), L"%y", fmtFileName(newName));
+
+ if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message!
+ lastError == ERROR_LOCK_VIOLATION)
+ {
+ const Zstring procList = getLockingProcessNames(oldName); //throw()
+ if (!procList.empty())
+ throw FileError(shortMsg + L"\n\n" + _("The file is locked by another process:") + L"\n" + procList);
+ }
+
if (lastError == ERROR_ACCESS_DENIED) //MoveFileEx may fail to rename a read-only file on a SAMBA-share -> (try to) handle this
{
const DWORD oldAttr = ::GetFileAttributes(oldNameFmt.c_str());
@@ -339,11 +405,13 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
}
}
- std::wstring errorMessage = _("Error moving file:") + L"\n\"" + oldName + L"\" ->\n\"" + newName + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
+ std::wstring errorMessage = shortMsg + L"\n\n" + getLastErrorFormatted(lastError);
if (lastError == ERROR_NOT_SAME_DEVICE)
throw ErrorDifferentVolume(errorMessage);
- else if (lastError == ERROR_FILE_EXISTS)
+
+ else if (lastError == ERROR_ALREADY_EXISTS || //-> used on Win7 x64
+ lastError == ERROR_FILE_EXISTS) //-> used by XP???
throw ErrorTargetExisting(errorMessage);
else
throw FileError(errorMessage);
@@ -353,8 +421,8 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
if (::rename(oldName.c_str(), newName.c_str()) != 0)
{
const int lastError = errno;
-
- std::wstring errorMessage = _("Error moving file:") + L"\n\"" + oldName + L"\" ->\n\"" + newName + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
+ std::wstring errorMessage = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", fmtFileName(oldName)), L"%y", fmtFileName(newName)) +
+ L"\n\n" + getLastErrorFormatted(lastError);
if (lastError == EXDEV)
throw ErrorDifferentVolume(errorMessage);
@@ -384,7 +452,7 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns
const DWORD rv = fun(filenameFmt.c_str(), //__in LPCTSTR lpszShortPath,
&buffer[0], //__out LPTSTR lpszLongPath,
- static_cast<DWORD>(buffer.size())); //__in DWORD cchBuffer
+ bufferSize); //__in DWORD cchBuffer
if (rv == 0 || rv >= buffer.size())
return Zstring();
@@ -394,7 +462,7 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns
Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short name
{
- const Zstring pathPrefix = filename.find(FILE_NAME_SEPARATOR) != Zstring::npos ?
+ const Zstring pathPrefix = contains(filename, FILE_NAME_SEPARATOR) ?
(beforeLast(filename, FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR) : Zstring();
Zstring extension = afterLast(afterLast(filename, FILE_NAME_SEPARATOR), Zchar('.')); //extension needn't contain reasonable data
@@ -416,7 +484,7 @@ Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short n
bool have8dot3NameClash(const Zstring& filename)
{
- if (filename.find(FILE_NAME_SEPARATOR) == Zstring::npos)
+ if (!contains(filename, FILE_NAME_SEPARATOR))
return false;
if (somethingExists(filename)) //name OR directory!
@@ -479,7 +547,7 @@ void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw Fil
{
renameFile_sub(oldName, newName); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
}
- catch (const FileError&)
+ catch (const ErrorTargetExisting&)
{
#ifdef FFS_WIN
//try to handle issues with already existing short 8.3 file names on Windows
@@ -501,7 +569,7 @@ class CopyCallbackImpl : public zen::CallbackCopyFile //callback functionality
public:
CopyCallbackImpl(const Zstring& sourceFile,
const Zstring& targetFile,
- CallbackMoveFile& callback) : sourceFile_(sourceFile),
+ CallbackMoveFile* callback) : sourceFile_(sourceFile),
targetFile_(targetFile),
moveCallback(callback) {}
@@ -509,9 +577,12 @@ public:
virtual void updateCopyStatus(UInt64 totalBytesTransferred)
{
- const Int64 delta = to<Int64>(totalBytesTransferred) - bytesReported;
- moveCallback.updateStatus(delta);
- bytesReported += delta;
+ if (moveCallback)
+ {
+ const Int64 delta = to<Int64>(totalBytesTransferred) - bytesReported;
+ moveCallback->updateStatus(delta);
+ bytesReported += delta;
+ }
}
private:
@@ -520,48 +591,44 @@ private:
const Zstring sourceFile_;
const Zstring targetFile_;
- CallbackMoveFile& moveCallback;
+ CallbackMoveFile* moveCallback; //optional
Int64 bytesReported;
};
-void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError;
+void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackMoveFile* callback) //throw FileError
{
if (callback) callback->onBeforeFileMove(sourceFile, targetFile); //call back once *after* work was done
- const bool targetExisting = fileExists(targetFile);
-
- if (targetExisting && !ignoreExisting) //test file existence: e.g. Linux might silently overwrite existing symlinks
- throw FileError(_("Error moving file:") + L"\n\"" + sourceFile + L"\" ->\n\"" + targetFile + L"\"" +
- L"\n\n" + _("Target file already existing!"));
-
- if (!targetExisting)
+ //first try to move the file directly without copying
+ try
{
- //try to move the file directly without copying
- try
- {
- renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume
- //great, we get away cheaply!
- if (callback) callback->objectProcessed();
- return;
- }
- //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file)
- catch (const ErrorDifferentVolume&) {}
+ renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ //great, we get away cheaply!
+ if (callback) callback->objectProcessed();
+ return;
+ }
+ //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file)
+ catch (const ErrorDifferentVolume&) {}
+ catch (const ErrorTargetExisting&) {}
+ //create target
+ if (!fileExists(targetFile)) //check even if ErrorTargetExisting: me may have clashed with a directory of the same name!!!
+ {
//file is on a different volume: let's copy it
if (symlinkExists(sourceFile))
copySymlink(sourceFile, targetFile, false); //throw FileError; don't copy filesystem permissions
else
{
- std::unique_ptr<CopyCallbackImpl> copyCallback(callback ? new CopyCallbackImpl(sourceFile, targetFile, *callback) : nullptr);
- copyFile(sourceFile, targetFile, false, true, copyCallback.get()); //throw FileError;
+ CopyCallbackImpl copyCallback(sourceFile, targetFile, callback);
+ copyFile(sourceFile, targetFile, false, true, &copyCallback); //throw FileError - permissions "false", transactional copy "true"
}
-
- //attention: if copy-operation was cancelled an exception is thrown => sourcefile is not deleted, as we wish!
}
+ //delete source
removeFile(sourceFile); //throw FileError
- //note: copying file is NOT undone in case of exception: currently this function is called in context of user-defined deletion dir, where this behavior is fine
+
+ //note: newly copied file is NOT deleted in case of exception: currently this function is called in context of user-defined deletion dir, where this behavior is fine
if (callback) callback->objectProcessed();
}
@@ -570,8 +637,8 @@ namespace
class TraverseOneLevel : public zen::TraverseCallback
{
public:
- typedef std::pair<Zstring, Zstring> NamePair;
- typedef std::vector<NamePair> NameList;
+ typedef std::pair<Zstring, Zstring> ShortLongNames;
+ typedef std::vector<ShortLongNames> NameList;
TraverseOneLevel(NameList& files, NameList& dirs) :
files_(files),
@@ -579,20 +646,20 @@ public:
virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details)
{
- files_.push_back(NamePair(shortName, fullName));
+ files_.push_back(std::make_pair(shortName, fullName));
}
virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details)
{
if (details.dirLink)
- dirs_.push_back(NamePair(shortName, fullName));
+ dirs_.push_back(std::make_pair(shortName, fullName));
else
- files_.push_back(NamePair(shortName, fullName));
+ files_.push_back(std::make_pair(shortName, fullName));
}
virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName)
{
- dirs_.push_back(NamePair(shortName, fullName));
+ dirs_.push_back(std::make_pair(shortName, fullName));
return nullptr; //DON'T traverse into subdirs; moveDirectory works recursively!
}
@@ -609,54 +676,51 @@ private:
struct RemoveCallbackImpl : public CallbackRemoveDir
{
- RemoveCallbackImpl(CallbackMoveFile& moveCallback) : moveCallback_(moveCallback) {}
+ RemoveCallbackImpl(CallbackMoveFile* moveCallback) : moveCallback_(moveCallback) {}
- virtual void notifyFileDeletion(const Zstring& filename) { moveCallback_.updateStatus(0); }
- virtual void notifyDirDeletion (const Zstring& dirname ) { moveCallback_.updateStatus(0); }
+ virtual void notifyFileDeletion(const Zstring& filename) { if (moveCallback_) moveCallback_->updateStatus(0); }
+ virtual void notifyDirDeletion (const Zstring& dirname ) { if (moveCallback_) moveCallback_->updateStatus(0); }
private:
RemoveCallbackImpl(const RemoveCallbackImpl&);
RemoveCallbackImpl& operator=(const RemoveCallbackImpl&);
- CallbackMoveFile& moveCallback_;
+ CallbackMoveFile* moveCallback_; //optional
};
}
-void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError
+void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, CallbackMoveFile* callback) //throw FileError
{
- if (callback) callback->onBeforeDirMove(sourceDir, targetDir); //call back once *after* work was done
-
- const bool targetExisting = dirExists(targetDir);
+ //note: we cannot support "throw exception if target already exists": If we did, we would have to do a full cleanup
+ //removing all newly created directories in case of an exception so that subsequent tries would not fail with "target already existing".
+ //However an exception may also happen during final deletion of source folder, in which case cleanup effectively leads to data loss!
- if (targetExisting && !ignoreExisting) //directory or symlink exists (or even a file... this error will be caught later)
- throw FileError(_("Error moving directory:") + L"\n\"" + sourceDir + L"\" ->\n\"" + targetDir + L"\"" +
- L"\n\n" + _("Target directory already existing!"));
-
- const bool isSymlink = symlinkExists(sourceDir);
+ if (callback) callback->onBeforeDirMove(sourceDir, targetDir); //call back once *after* work was done
- if (!targetExisting)
+ //first try to move the directory directly without copying
+ try
{
- //first try to move the directory directly without copying
- try
- {
- renameFile(sourceDir, targetDir); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
- //great, we get away cheaply!
- if (callback) callback->objectProcessed();
- return;
- }
- //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&) {}
+ renameFile(sourceDir, targetDir); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ //great, we get away cheaply!
+ if (callback) callback->objectProcessed();
+ return;
+ }
+ //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&) {}
- //create target
- if (isSymlink)
+ //create target
+ if (symlinkExists(sourceDir))
+ {
+ if (!dirExists(targetDir))
copySymlink(sourceDir, targetDir, false); //throw FileError -> don't copy permissions
- else
- createDirectory(targetDir, sourceDir, false); //throw FileError
}
-
- if (!isSymlink) //handle symbolic links
+ 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
+
//move files/folders recursively
TraverseOneLevel::NameList fileList; //list of names: 1. short 2.long
TraverseOneLevel::NameList dirList; //
@@ -665,30 +729,26 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool
TraverseOneLevel traverseCallback(fileList, dirList);
traverseFolder(sourceDir, false, traverseCallback); //traverse one level, don't follow symlinks
- const Zstring targetDirFormatted = endsWith(targetDir, FILE_NAME_SEPARATOR) ? //ends with path separator
- targetDir :
- targetDir + FILE_NAME_SEPARATOR;
+ const Zstring targetDirPf = appendSeparator(targetDir);
//move files
for (TraverseOneLevel::NameList::const_iterator i = fileList.begin(); i != fileList.end(); ++i)
- moveFile(i->second, targetDirFormatted + i->first, ignoreExisting, callback); //throw FileError, ErrorTargetExisting
+ moveFile(i->second, targetDirPf + i->first, callback); //throw FileError
//move directories
for (TraverseOneLevel::NameList::const_iterator i = dirList.begin(); i != dirList.end(); ++i)
- ::moveDirectoryImpl(i->second, targetDirFormatted + i->first, ignoreExisting, callback);
-
- //attention: if move-operation was cancelled an exception is thrown => sourceDir is not deleted, as we wish!
+ ::moveDirectoryImpl(i->second, targetDirPf + i->first, callback);
}
//delete source
- std::unique_ptr<RemoveCallbackImpl> removeCallback(callback ? new RemoveCallbackImpl(*callback) : nullptr);
- removeDirectory(sourceDir, removeCallback.get()); //throw FileError;
+ RemoveCallbackImpl removeCallback(callback);
+ removeDirectory(sourceDir, &removeCallback); //throw FileError
if (callback) callback->objectProcessed();
}
-void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError
+void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, CallbackMoveFile* callback) //throw FileError
{
#ifdef FFS_WIN
const Zstring& sourceDirFormatted = sourceDir;
@@ -705,7 +765,7 @@ void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool
targetDir;
#endif
- ::moveDirectoryImpl(sourceDirFormatted, targetDirFormatted, ignoreExisting, callback);
+ ::moveDirectoryImpl(sourceDirFormatted, targetDirFormatted, callback);
}
@@ -764,7 +824,7 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
#elif defined FFS_LINUX
if (::unlink(directory.c_str()) != 0)
#endif
- throw FileError(_("Error deleting directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
if (callback)
callback->notifyDirDeletion(directory); //once per symlink
@@ -797,7 +857,7 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
#else
if (::rmdir(directory.c_str()) != 0)
#endif
- throw FileError(_("Error deleting directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
if (callback)
callback->notifyDirDeletion(directory); //and once per folder
@@ -813,7 +873,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
//####################################### DST hack ###########################################
if (dst::isFatDrive(filename)) //throw()
{
- const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw (std::runtime_error)
+ const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw std::runtime_error
creationTime = encodedTime.createTimeRaw;
lastWriteTime = encodedTime.writeTimeRaw;
}
@@ -833,21 +893,20 @@ 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, [ = ]()
+ FileUpdateHandle targetHandle(filename, [=]
{
return ::CreateFile(applyLongPathPrefix(filename).c_str(),
- GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory
- (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks
- nullptr);
+ GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
+ 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(_("Error changing modification time:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
-
+ 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
@@ -862,7 +921,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
isNullTime(creationTime) ? nullptr : &creationTime,
nullptr,
&lastWriteTime))
- throw FileError(_("Error changing modification time:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
#ifndef NDEBUG //dst hack: verify data written
if (dst::isFatDrive(filename) && !dirExists(filename)) //throw()
@@ -886,7 +945,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
// set new "last write time"
if (::utime(filename.c_str(), &newTimes) != 0)
- throw FileError(_("Error changing modification time:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
}
else
{
@@ -898,7 +957,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
newTimes[1].tv_usec = 0;
if (::lutimes(filename.c_str(), newTimes) != 0)
- throw FileError(_("Error changing modification time:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
}
#endif
}
@@ -907,11 +966,12 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
bool zen::supportsPermissions(const Zstring& dirname) //throw FileError
{
#ifdef FFS_WIN
- std::vector<wchar_t> buffer(MAX_PATH + 1);
+ const DWORD bufferSize = MAX_PATH + 1;
+ std::vector<wchar_t> buffer(bufferSize);
if (!::GetVolumePathName(dirname.c_str(), //__in LPCTSTR lpszFileName,
&buffer[0], //__out LPTSTR lpszVolumePathName,
- static_cast<DWORD>(buffer.size()))) //__in DWORD cchBufferLength
- throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ bufferSize)) //__in DWORD cchBufferLength
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)) + L"\n\n" + getLastErrorFormatted());
DWORD fsFlags = 0;
if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName,
@@ -922,51 +982,10 @@ bool zen::supportsPermissions(const Zstring& dirname) //throw FileError
&fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
- throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)) + L"\n\n" + getLastErrorFormatted());
return (fsFlags & FILE_PERSISTENT_ACLS) != 0;
-
- // -> the following approach is *only* working since Windows Vista:
- // const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(dirname).c_str(),
- // 0,
- // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- // nullptr,
- // OPEN_EXISTING,
- // FILE_FLAG_BACKUP_SEMANTICS, // | FILE_FLAG_OPEN_REPARSE_POINT -> follow symlinks
- // nullptr);
- // if (hDir == INVALID_HANDLE_VALUE)
- // throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
- // ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
- //
- // //dynamically load windows API function (existing since Windows XP)
- // typedef BOOL (WINAPI* GetVolumeInformationByHandleWFun)(HANDLE hFile,
- // LPWSTR lpVolumeNameBuffer,
- // DWORD nVolumeNameSize,
- // LPDWORD lpVolumeSerialNumber,
- // LPDWORD lpMaximumComponentLength,
- // LPDWORD lpFileSystemFlags,
- // LPWSTR lpFileSystemNameBuffer,
- // DWORD nFileSystemNameSize);
- //
- // const SysDllFun<GetVolumeInformationByHandleWFun> getVolumeInformationByHandleW(L"kernel32.dll", "GetVolumeInformationByHandleW"); //available since Windows Vista
- // if (!getVolumeInformationByHandleW)
- // return true; //Windows XP, 2000 -> do not show this error message
- // //throw FileError(rror loading library function+ L"\n\"" + L"GetVolumeInformationByHandleW" + L"\"");
- //
- // DWORD fileSystemFlags = 0;
- // if (!getVolumeInformationByHandleW(hDir, //__in HANDLE hFile,
- // nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
- // 0, //__in DWORD nVolumeNameSize,
- // nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
- // nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
- // &fileSystemFlags, //__out_opt LPDWORD lpFileSystemFlags,
- // nullptr, //__out LPTSTR lpFileSystemNameBuffer,
- // 0)) //__in DWORD nFileSystemNameSize
- // throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
- //
- // return (fileSystemFlags & FILE_PERSISTENT_ACLS) != 0;
-
#elif defined FFS_LINUX
return true;
#endif
@@ -982,12 +1001,12 @@ Zstring getSymlinkTargetPath(const Zstring& symlink) //throw FileError
const HANDLE hDir = ::CreateFile(applyLongPathPrefix(symlink).c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory
nullptr);
if (hDir == INVALID_HANDLE_VALUE)
- throw FileError(_("Error resolving symbolic link:") + L"\n\"" + symlink + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(symlink)) + L"\n\n" + getLastErrorFormatted());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
//dynamically load windows API function
@@ -997,7 +1016,7 @@ Zstring getSymlinkTargetPath(const Zstring& symlink) //throw FileError
DWORD dwFlags);
const SysDllFun<GetFinalPathNameByHandleWFunc> getFinalPathNameByHandle(L"kernel32.dll", "GetFinalPathNameByHandleW");
if (!getFinalPathNameByHandle)
- throw FileError(_("Error loading library function:") + L"\n\"" + L"GetFinalPathNameByHandleW" + L"\"");
+ throw FileError(replaceCpy(_("Cannot find system function %x."), L"%x", L"\"GetFinalPathNameByHandleW\""));
const DWORD BUFFER_SIZE = 10000;
std::vector<wchar_t> targetPath(BUFFER_SIZE);
@@ -1007,7 +1026,7 @@ Zstring getSymlinkTargetPath(const Zstring& symlink) //throw FileError
FILE_NAME_NORMALIZED); //__in DWORD dwFlags
if (charsWritten >= BUFFER_SIZE || charsWritten == 0)
{
- std::wstring errorMessage = _("Error resolving symbolic link:") + L"\n\"" + symlink + L"\"";
+ std::wstring errorMessage = replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(symlink));
if (charsWritten == 0)
errorMessage += L"\n\n" + getLastErrorFormatted();
throw FileError(errorMessage);
@@ -1032,7 +1051,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem
return;
- throw FileError(_("Error reading security context:") + L"\n\"" + source + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read security context of %x."), L"%x", fmtFileName(source)) + L"\n\n" + getLastErrorFormatted());
}
ZEN_ON_SCOPE_EXIT(::freecon(contextSource));
@@ -1060,7 +1079,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
::setfilecon(target.c_str(), contextSource) :
::lsetfilecon(target.c_str(), contextSource);
if (rv3 < 0)
- throw FileError(_("Error writing security context:") + L"\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtFileName(target)) + L"\n\n" + getLastErrorFormatted());
}
#endif //HAVE_SELINUX
@@ -1070,23 +1089,18 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
{
#ifdef FFS_WIN
//setting privileges requires admin rights!
- try
- {
- //enable privilege: required to read/write SACL information (only)
- activatePrivilege(SE_SECURITY_NAME); //polling allowed...
- //Note: trying to copy SACL (SACL_SECURITY_INFORMATION) may return ERROR_PRIVILEGE_NOT_HELD (1314) on Samba shares. This is not due to missing privileges!
- //However, this is okay, since copying NTFS permissions doesn't make sense in this case anyway
- //enable privilege: required to copy owner information
- activatePrivilege(SE_RESTORE_NAME);
+ //enable privilege: required to read/write SACL information (only)
+ activatePrivilege(SE_SECURITY_NAME); //throw FileError
+ //Note: trying to copy SACL (SACL_SECURITY_INFORMATION) may return ERROR_PRIVILEGE_NOT_HELD (1314) on Samba shares. This is not due to missing privileges!
+ //However, this is okay, since copying NTFS permissions doesn't make sense in this case anyway
+
+ //enable privilege: required to copy owner information
+ activatePrivilege(SE_RESTORE_NAME); //throw FileError
+
+ //the following privilege may be required according to http://msdn.microsoft.com/en-us/library/aa364399(VS.85).aspx (although not needed nor active in my tests)
+ activatePrivilege(SE_BACKUP_NAME); //throw FileError
- //the following privilege may be required according to http://msdn.microsoft.com/en-us/library/aa364399(VS.85).aspx (although not needed nor active in my tests)
- activatePrivilege(SE_BACKUP_NAME);
- }
- catch (const FileError& e)
- {
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + e.toString());
- }
//in contrast to ::SetSecurityInfo(), ::SetFileSecurity() seems to honor the "inherit DACL/SACL" flags
//CAVEAT: if a file system does not support ACLs, GetFileSecurity() will return successfully with a *valid* security descriptor containing *no* ACL entries!
@@ -1110,7 +1124,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
if (bytesNeeded > buffer.size())
buffer.resize(bytesNeeded);
else
- throw FileError(_("Error copying file permissions:") + L"\n\"" + sourceResolved + L"\" ->\n\"" + targetResolved + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (R)");
+ throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(sourceResolved)) + L"\n\n" + getLastErrorFormatted());
}
SECURITY_DESCRIPTOR& secDescr = reinterpret_cast<SECURITY_DESCRIPTOR&>(buffer[0]);
@@ -1121,7 +1135,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
if (!::GetSecurityDescriptorControl(&secDescr, // __in PSECURITY_DESCRIPTOR pSecurityDescriptor,
&secCtrl, // __out PSECURITY_DESCRIPTOR_CONTROL pControl,
&ctrlRev)) //__out LPDWORD lpdwRevision
- throw FileError(_("Error copying file permissions:") + L"\n\"" + sourceResolved + L"\" ->\n\"" + targetResolved + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (C)");
+ throw FileErro
}
//interesting flags:
//#define SE_DACL_PRESENT (0x0004)
@@ -1134,7 +1148,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, //__in SECURITY_INFORMATION SecurityInformation,
&secDescr)) //__in PSECURITY_DESCRIPTOR pSecurityDescriptor
- throw FileError(_("Error copying file permissions:") + L"\n\"" + sourceResolved + L"\" ->\n\"" + targetResolved + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (W)");
+ throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(targetResolved)) + L"\n\n" + getLastErrorFormatted());
/*
PSECURITY_DESCRIPTOR buffer = nullptr;
@@ -1148,12 +1162,12 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
const HANDLE hSource = ::CreateFile(applyLongPathPrefix(source).c_str(),
READ_CONTROL | ACCESS_SYSTEM_SECURITY, //ACCESS_SYSTEM_SECURITY required for SACL access
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory
nullptr);
if (hSource == INVALID_HANDLE_VALUE)
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (OR)");
+ throw FileError
ZEN_ON_SCOPE_EXIT(::CloseHandle(hSource));
// DWORD rc = ::GetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(source).c_str()), -> does NOT dereference symlinks!
@@ -1167,7 +1181,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
&sacl, //__out_opt PACL *ppSacl,
&buffer); //__out_opt PSECURITY_DESCRIPTOR *ppSecurityDescriptor
if (rc != ERROR_SUCCESS)
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted(rc) + L" (R)");
+ throw FileError
ZEN_ON_SCOPE_EXIT(::LocalFree(buffer));
SECURITY_DESCRIPTOR_CONTROL secCtrl = 0;
@@ -1176,23 +1190,23 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
if (!::GetSecurityDescriptorControl(buffer, // __in PSECURITY_DESCRIPTOR pSecurityDescriptor,
&secCtrl, // __out PSECURITY_DESCRIPTOR_CONTROL pControl,
&ctrlRev))//__out LPDWORD lpdwRevision
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted(rc) + L" (C)");
+ throw FileError
}
//may need to remove the readonly-attribute
- FileUpdateHandle targetHandle(target, [ = ]()
+ FileUpdateHandle targetHandle(target, [=]
{
return ::CreateFile(applyLongPathPrefix(target).c_str(), // lpFileName
GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, // dwDesiredAccess: all four seem to be required!!!
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // dwShareMode
- 0, // lpSecurityAttributes
+ nullptr, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), // dwFlagsAndAttributes
nullptr); // hTemplateFile
});
if (targetHandle.get() == INVALID_HANDLE_VALUE)
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (OW)");
+ throw FileError
SECURITY_INFORMATION secFlags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
@@ -1213,7 +1227,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
sacl); //__in_opt PACL pSacl
if (rc != ERROR_SUCCESS)
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted(rc) + L" (W)");
+ throw FileError
*/
#elif defined FFS_LINUX
@@ -1225,17 +1239,21 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
struct stat fileInfo = {};
if (procSl == SYMLINK_FOLLOW)
{
- if (::stat(source.c_str(), &fileInfo) != 0 ||
- ::chown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights!
+ if (::stat(source.c_str(), &fileInfo) != 0)
+ throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)) + L"\n\n" + getLastErrorFormatted());
+
+ if (::chown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights!
::chmod(target.c_str(), fileInfo.st_mode) != 0)
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (R)");
+ throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)) + L"\n\n" + getLastErrorFormatted());
}
else
{
- if (::lstat(source.c_str(), &fileInfo) != 0 ||
- ::lchown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights!
+ if (::lstat(source.c_str(), &fileInfo) != 0)
+ throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)) + L"\n\n" + getLastErrorFormatted());
+
+ if (::lchown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights!
(!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0)) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod()
- throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (W)");
+ throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)) + L"\n\n" + getLastErrorFormatted());
}
#endif
}
@@ -1255,7 +1273,7 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
#endif
{
if (level != 0) return;
- throw FileError(_("Error creating directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot create directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}
if (!templateDir.empty())
@@ -1295,7 +1313,7 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
HANDLE hDir = ::CreateFile(applyLongPathPrefix(directory).c_str(),
GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
@@ -1319,7 +1337,7 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
}
}
#endif
- zen::ScopeGuard guardNewDir = zen::makeGuard([&] { removeDirectory(directory); }); //ensure cleanup:
+ zen::ScopeGuard guardNewDir = zen::makeGuard([&] { try { removeDirectory(directory); } catch (...) {} }); //ensure cleanup:
//enforce copying file permissions: it's advertized on GUI...
if (copyFilePermissions)
@@ -1404,7 +1422,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
const SysDllFun<CreateSymbolicLinkFunc> createSymbolicLink(L"kernel32.dll", "CreateSymbolicLinkW");
if (!createSymbolicLink)
- throw FileError(_("Error loading library function:") + L"\n\"" + L"CreateSymbolicLinkW" + L"\"");
+ throw FileError(replaceCpy(_("Cannot find system function %x."), L"%x", L"\"CreateSymbolicLinkW\""));
if (!createSymbolicLink(targetLink.c_str(), //__in LPTSTR lpSymlinkFileName, - seems no long path prefix is required...
linkPath.c_str(), //__in LPTSTR lpTargetFileName,
@@ -1412,17 +1430,22 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
#elif defined FFS_LINUX
if (::symlink(linkPath.c_str(), targetLink.c_str()) != 0)
#endif
- throw FileError(_("Error copying symbolic link:") + L"\n\"" + sourceLink + L"\" ->\n\"" + targetLink + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", fmtFileName(sourceLink)), L"%y", fmtFileName(targetLink)) +
+ L"\n\n" + getLastErrorFormatted());
//allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist
zen::ScopeGuard guardNewDir = zen::makeGuard([&]
{
+ try
+ {
#ifdef FFS_WIN
- if (isDirLink)
- removeDirectory(targetLink);
- else
+ if (isDirLink)
+ removeDirectory(targetLink);
+ else
#endif
- removeFile(targetLink);
+ removeFile(targetLink);
+ }
+ catch (...) {}
});
//file times: essential for a symlink: enforce this! (don't just try!)
@@ -1440,72 +1463,423 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
namespace
{
-Zstring createTempName(const Zstring& filename)
+#ifdef FFS_WIN
+/*
+ CopyFileEx() BackupRead() FileRead()
+ --------------------------------------------
+Attributes YES NO NO
+create time NO NO NO
+ADS YES YES NO
+Encrypted YES NO(silent fail!) NO
+Compressed NO NO NO
+Sparse NO YES NO
+Nonstandard FS YES UNKNOWN -> issues writing ADS to Samba, issues reading from NAS, error copying files having "blocked" state... ect.
+PERF - 6% faster
+
+Mark stream as compressed: FSCTL_SET_COMPRESSION - compatible with both BackupRead() and FileRead()
+
+
+Current support for combinations of NTFS extended attributes:
+
+source attr | tf normal | tf compressed | tf encrypted | handled by
+============|==================================================================
+ --- | --- -C- E-- copyFileWindowsDefault
+ --S | --S -CS E-S copyFileWindowsSparse
+ -C- | --- (NOK) -C- E-- copyFileWindowsDefault
+ -CS | -CS -CS E-S copyFileWindowsSparse
+ E-- | E-- E-- E-- copyFileWindowsDefault
+ E-S | E-- (NOK) E-- (NOK) E-- (NOK) copyFileWindowsDefault -> may fail with ERROR_DISK_FULL!!
+
+tf := target folder
+E := encrypted
+C := compressed
+S := sparse
+NOK := current behavior is not optimal/OK yet.
+
+Note: - if target parent folder is compressed or encrypted, both attributes are added automatically during file creation!
+ - "compressed" and "encrypted" are mutually exclusive: http://support.microsoft.com/kb/223093/en-us
+*/
+
+
+//due to issues on non-NTFS volumes, we should use the copy-as-sparse routine only if required and supported!
+bool canCopyAsSparse(HANDLE hSource, const Zstring& targetFile) //throw ()
{
- Zstring output = filename + zen::TEMP_FILE_ENDING;
+ BY_HANDLE_FILE_INFORMATION fileInfoSource = {};
+ if (!::GetFileInformationByHandle(hSource, &fileInfoSource))
+ return false;
- //ensure uniqueness
- for (int i = 1; somethingExists(output); ++i)
- output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
+ const bool sourceIsEncrypted = (fileInfoSource.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
+ const bool sourceIsSparse = (fileInfoSource.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0;
- return output;
+ if (sourceIsEncrypted || !sourceIsSparse) //BackupRead() silently fails reading encrypted files!
+ return false; //small perf optimization: don't check "targetFile" if not needed
+
+ //------------------------------------------------------------------------------------
+ const DWORD bufferSize = 10000;
+ std::vector<wchar_t> buffer(bufferSize);
+
+ //full pathName need not yet exist!
+ if (!::GetVolumePathName(targetFile.c_str(), //__in LPCTSTR lpszFileName,
+ &buffer[0], //__out LPTSTR lpszVolumePathName,
+ bufferSize)) //__in DWORD cchBufferLength
+ return false;
+
+ DWORD fsFlagsTarget = 0;
+ if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName
+ nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
+ 0, //__in DWORD nVolumeNameSize,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ &fsFlagsTarget, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
+ return false;
+
+ const bool targetSupportSparse = (fsFlagsTarget & FILE_SUPPORTS_SPARSE_FILES) != 0;
+
+ return targetSupportSparse;
+ //both source and target must not be FAT since copyFileWindowsSparse() does no DST hack! implicitly guaranteed at this point!
}
-#ifdef FFS_WIN
-class CallbackData
+
+bool canCopyAsSparse(const Zstring& sourceFile, const Zstring& targetFile) //throw ()
{
-public:
- CallbackData(CallbackCopyFile* cb, //may be nullptr
- const Zstring& sourceFile,
- const Zstring& targetFile) :
- userCallback(cb),
- sourceFile_(sourceFile),
- targetFile_(targetFile),
- exceptionInUserCallback(false) {}
+ HANDLE hFileSource = ::CreateFile(applyLongPathPrefix(sourceFile).c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read files that are open in other applications
+ nullptr,
+ OPEN_EXISTING,
+ 0,
+ nullptr);
+ if (hFileSource == INVALID_HANDLE_VALUE)
+ return false;
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFileSource));
+
+ return canCopyAsSparse(hFileSource, targetFile); //throw ()
+}
- CallbackCopyFile* userCallback; //optional!
- const Zstring& sourceFile_;
- const Zstring& targetFile_;
- //there is mixed responsibility in this class, pure read-only data and abstraction for error reporting
- //however we need to keep it together as ::CopyFileEx() requires!
+//precondition: canCopyAsSparse() must return "true"!
+void copyFileWindowsSparse(const Zstring& sourceFile,
+ const Zstring& targetFile,
+ CallbackCopyFile* callback,
+ FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+{
+ assert(canCopyAsSparse(sourceFile, targetFile));
+
+ //comment suggests "FILE_FLAG_BACKUP_SEMANTICS + SE_BACKUP_NAME" may be needed: http://msdn.microsoft.com/en-us/library/windows/desktop/aa362509(v=vs.85).aspx
+ try { activatePrivilege(SE_BACKUP_NAME); }
+ catch (const FileError&) {}
+ try { activatePrivilege(SE_RESTORE_NAME); }
+ catch (const FileError&) {}
+
+ //open sourceFile for reading
+ HANDLE hFileSource = ::CreateFile(applyLongPathPrefix(sourceFile).c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read files that are open in other applications
+ nullptr,
+ OPEN_EXISTING, //FILE_FLAG_OVERLAPPED must not be used!
+ FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_BACKUP_SEMANTICS, //FILE_FLAG_NO_BUFFERING should not be used!
+ nullptr);
+ if (hFileSource == INVALID_HANDLE_VALUE)
+ {
+ const DWORD lastError = ::GetLastError();
+
+ const std::wstring shortMsg = replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile));
+
+ //if file is locked throw "ErrorFileLocked" instead!
+ if (lastError == ERROR_SHARING_VIOLATION ||
+ lastError == ERROR_LOCK_VIOLATION)
+ {
+ const Zstring procList = getLockingProcessNames(sourceFile); //throw()
+ throw ErrorFileLocked(shortMsg + L"\n\n" + (!procList.empty() ? _("The file is locked by another process:") + L"\n" + procList : getLastErrorFormatted(lastError)));
+ }
- void reportUserException(const UInt64& bytesTransferred)
+ throw FileError(shortMsg + L"\n\n" + getLastErrorFormatted(lastError) + L" (open)");
+ }
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFileSource));
+
+ //----------------------------------------------------------------------
+ BY_HANDLE_FILE_INFORMATION fileInfoSource = {};
+ if (!::GetFileInformationByHandle(hFileSource, &fileInfoSource))
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" + getLastErrorFormatted());
+
+ //----------------------------------------------------------------------
+ const DWORD validAttribs = FILE_ATTRIBUTE_READONLY |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_ARCHIVE | //those two are not set properly (not worse than ::CopyFileEx())
+ FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; //
+ //FILE_ATTRIBUTE_ENCRYPTED -> no!
+
+ //create targetFile and open it for writing
+ HANDLE hFileTarget = ::CreateFile(applyLongPathPrefix(targetFile).c_str(),
+ GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
+ FILE_SHARE_READ | FILE_SHARE_DELETE,
+ nullptr,
+ CREATE_NEW,
+ FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_BACKUP_SEMANTICS | (fileInfoSource.dwFileAttributes & validAttribs),
+ //FILE_FLAG_OVERLAPPED must not be used! FILE_FLAG_NO_BUFFERING should not be used!
+ nullptr);
+ if (hFileTarget == INVALID_HANDLE_VALUE)
{
- exceptionInUserCallback = true;
- bytesTransferredOnException = bytesTransferred;
+ const DWORD lastError = ::GetLastError();
+ const std::wstring errorMessage = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted(lastError) + L" (open)";
+
+ if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
+ lastError == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
+ throw ErrorTargetExisting(errorMessage);
+
+ if (lastError == ERROR_PATH_NOT_FOUND)
+ throw ErrorTargetPathMissing(errorMessage);
+
+ throw FileError(errorMessage);
}
+ ScopeGuard guardTarget = makeGuard([&] { try { removeFile(targetFile); } catch (...) {} }); //transactional behavior: guard just after opening target and before managing hFileOut
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFileTarget));
- void reportError(const std::wstring& message) { errorMsg = message; }
+ //----------------------------------------------------------------------
+ BY_HANDLE_FILE_INFORMATION fileInfoTarget = {};
+ if (!::GetFileInformationByHandle(hFileTarget, &fileInfoTarget))
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
- void evaluateErrors() //throw
+ //return up-to-date file attributes
+ if (newAttrib)
{
- if (exceptionInUserCallback)
+ newAttrib->fileSize = UInt64(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh);
+ newAttrib->modificationTime = toTimeT(fileInfoSource.ftLastWriteTime); //no DST hack (yet)
+ newAttrib->sourceFileId = extractFileID(fileInfoSource);
+ newAttrib->targetFileId = extractFileID(fileInfoTarget);
+ }
+
+ //----------------------------------------------------------------------
+ DWORD fsFlagsTarget = 0;
+ {
+ const DWORD bufferSize = 10000;
+ std::vector<wchar_t> buffer(bufferSize);
+
+ //full pathName need not yet exist!
+ if (!::GetVolumePathName(targetFile.c_str(), //__in LPCTSTR lpszFileName,
+ &buffer[0], //__out LPTSTR lpszVolumePathName,
+ bufferSize)) //__in DWORD cchBufferLength
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
+
+ //GetVolumeInformationByHandleW would be a better solution, but it is supported beginning with Vista only!
+ if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName
+ nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
+ 0, //__in DWORD nVolumeNameSize,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ &fsFlagsTarget, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
+ }
+
+ //----------------------------------------------------------------------
+ const bool sourceIsCompressed = (fileInfoSource.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
+ const bool sourceIsSparse = (fileInfoSource.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0;
+
+ const bool targetSupportsCompressed = (fsFlagsTarget & FILE_FILE_COMPRESSION ) != 0;
+ const bool targetSupportsSparse = (fsFlagsTarget & FILE_SUPPORTS_SPARSE_FILES) != 0;
+
+ //----------------------------------------------------------------------
+ if (sourceIsCompressed && targetSupportsCompressed)
+ {
+ USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
+ DWORD bytesReturned = 0;
+ if (!DeviceIoControl(hFileTarget, //handle to file or directory
+ FSCTL_SET_COMPRESSION, //dwIoControlCode
+ &cmpState, //input buffer
+ sizeof(cmpState), //size of input buffer
+ nullptr, //lpOutBuffer
+ 0, //OutBufferSize
+ &bytesReturned, //number of bytes returned
+ nullptr)) //OVERLAPPED structure
{
- assert(userCallback);
- if (userCallback)
- userCallback->updateCopyStatus(bytesTransferredOnException); //rethrow (hopefully!)
+ //-> if target folder is encrypted this call will legitimately fail with ERROR_INVALID_FUNCTION
+ //throw FileError
}
- if (!errorMsg.empty())
- throw FileError(errorMsg);
}
- void setNewAttr(const FileAttrib& attr) { newAttrib = attr; }
+ //although it seems the sparse attribute is set automatically by BackupWrite, we are required to do this manually: http://support.microsoft.com/kb/271398/en-us
+ //Quote: It is the responsibility of the backup utility to apply file attributes to a file after it is restored by using BackupWrite.
+ //The application should retrieve the attributes by using GetFileAttributes prior to creating a backup with BackupRead.
+ //If a file originally had the sparse attribute (FILE_ATTRIBUTE_SPARSE_FILE), the backup utility must explicitly set the
+ //attribute on the restored file. The attribute can be set by using the DeviceIoControl function with the FSCTL_SET_SPARSE flag.
+
+ if (sourceIsSparse && targetSupportsSparse)
+ {
+ DWORD bytesReturned = 0;
+ if (!DeviceIoControl(hFileTarget, //handle to file
+ FSCTL_SET_SPARSE, //dwIoControlCode
+ nullptr, //input buffer
+ 0, //size of input buffer
+ nullptr, //lpOutBuffer
+ 0, //OutBufferSize
+ &bytesReturned, //number of bytes returned
+ nullptr)) //OVERLAPPED structure
+ throw FileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(targetFile)) +
+ L"\n\n" + zen::getLastErrorFormatted() + L" (NTFS sparse)");
+ }
+
+ //----------------------------------------------------------------------
+ const DWORD BUFFER_SIZE = 512 * 1024; //512 kb seems to be a reasonable buffer size - must be greater than sizeof(WIN32_STREAM_ID)
+ static boost::thread_specific_ptr<std::vector<BYTE>> cpyBuf;
+ if (!cpyBuf.get())
+ cpyBuf.reset(new std::vector<BYTE>(BUFFER_SIZE));
+ std::vector<BYTE>& buffer = *cpyBuf;
+
+ LPVOID contextRead = nullptr; //manage context for BackupRead()/BackupWrite()
+ LPVOID contextWrite = nullptr; //
+
+ ZEN_ON_SCOPE_EXIT(
+ if (contextRead ) ::BackupRead (0, nullptr, 0, nullptr, true, false, &contextRead); //lpContext must be passed [...] all other parameters are ignored.
+ if (contextWrite) ::BackupWrite(0, nullptr, 0, nullptr, true, false, &contextWrite); );
+
+
+ //stream-copy sourceFile to targetFile
+ UInt64 totalBytesTransferred; //may be larger than file size! context information + ADS!
+ bool eof = false;
+ do
+ {
+ DWORD bytesRead = 0;
+ if (!::BackupRead(hFileSource, //__in HANDLE hFile,
+ &buffer[0], //__out LPBYTE lpBuffer,
+ BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead,
+ &bytesRead, //__out LPDWORD lpNumberOfBytesRead,
+ false, //__in BOOL bAbort,
+ false, //__in BOOL bProcessSecurity,
+ &contextRead)) //__out LPVOID *lpContext
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" + getLastErrorFormatted()); //better use fine-granular error messages "reading/writing"!
+
+ if (bytesRead > BUFFER_SIZE)
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" + L"(buffer overflow)");
+
+ if (bytesRead < BUFFER_SIZE)
+ eof = true;
+
+ DWORD bytesWritten = 0;
+ if (!::BackupWrite(hFileTarget, //__in HANDLE hFile,
+ &buffer[0], //__in LPBYTE lpBuffer,
+ bytesRead, //__in DWORD nNumberOfBytesToWrite,
+ &bytesWritten, //__out LPDWORD lpNumberOfBytesWritten,
+ false, //__in BOOL bAbort,
+ false, //__in BOOL bProcessSecurity,
+ &contextWrite)) //__out LPVOID *lpContext
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
+
+ if (bytesWritten != bytesRead)
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + L"(incomplete write)");
+
+ totalBytesTransferred += bytesRead;
+
+ //invoke callback method to update progress indicators
+ if (callback)
+ callback->updateCopyStatus(totalBytesTransferred); //throw X!
+ }
+ while (!eof);
+
+ //DST hack not required, since both source and target volumes cannot be FAT!
+
+ //::BackupRead() silently fails reading encrypted files -> double check!
+ if (totalBytesTransferred == 0U && UInt64(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh) != 0U)
+ //note: there is no guaranteed ordering relation beween bytes transferred and file size! Consider ADS (>) and compressed/sparse files (<)!
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" + L"(unknown error)");
+
+ //time needs to be set at the end: BackupWrite() changes modification time
+ if (!::SetFileTime(hFileTarget,
+ &fileInfoSource.ftCreationTime,
+ nullptr,
+ &fileInfoSource.ftLastWriteTime))
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
+
+ guardTarget.dismiss();
+
+ /*
+ //create sparse file for testing:
+ HANDLE hSparse = ::CreateFile(L"C:\\sparse.file",
+ GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ CREATE_NEW,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ nullptr);
+ if (hFileTarget == INVALID_HANDLE_VALUE)
+ throw 1;
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hSparse));
+
+ DWORD br = 0;
+ if (!::DeviceIoControl(hSparse, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &br,nullptr))
+ throw 1;
+
+ LARGE_INTEGER liDistanceToMove = {};
+ liDistanceToMove.QuadPart = 1024 * 1024 * 1024; //create 5 TB sparse file
+ liDistanceToMove.QuadPart *= 5 * 1024; //maximum file size on NTFS: 16 TB - 64 kB
+ if (!::SetFilePointerEx(hSparse, liDistanceToMove, nullptr, FILE_BEGIN))
+ throw 1;
+
+ if (!SetEndOfFile(hSparse))
+ throw 1;
+
+ FILE_ZERO_DATA_INFORMATION zeroInfo = {};
+ zeroInfo.BeyondFinalZero.QuadPart = liDistanceToMove.QuadPart;
+ if (!::DeviceIoControl(hSparse, FSCTL_SET_ZERO_DATA, &zeroInfo, sizeof(zeroInfo), nullptr, 0, &br, nullptr))
+ throw 1;
+ */
+}
+
+
+DEFINE_NEW_FILE_ERROR(ErrorShouldCopyAsSparse);
+
+class ErrorHandling
+{
+public:
+ ErrorHandling() : shouldCopyAsSparse(false) {}
- FileAttrib getSrcAttr() const
+ void reportUserException(CallbackCopyFile& userCallback, const UInt64& bytesTransferred)
{
- assert(newAttrib.modificationTime != 0);
- return newAttrib;
+ exceptionInUserCallback.reset(new std::pair<CallbackCopyFile*, UInt64>(&userCallback, bytesTransferred));
+ }
+
+ void reportErrorShouldCopyAsSparse() { shouldCopyAsSparse = true; }
+
+ void reportError(const std::wstring& message) { errorMsg = message; }
+
+ void evaluateErrors() //throw X
+ {
+ if (shouldCopyAsSparse)
+ throw ErrorShouldCopyAsSparse(L"sparse dummy value");
+
+ if (exceptionInUserCallback)
+ exceptionInUserCallback->first->updateCopyStatus(exceptionInUserCallback->second); //rethrow (hopefully!)
+
+ if (!errorMsg.empty())
+ throw FileError(errorMsg);
}
private:
- CallbackData(const CallbackData&);
- CallbackData& operator=(const CallbackData&);
+ bool shouldCopyAsSparse;
+ std::wstring errorMsg; //these two are exclusive!
+ std::unique_ptr<std::pair<CallbackCopyFile*, UInt64>> exceptionInUserCallback; //
+};
+
+
+struct CallbackData
+{
+ CallbackData(CallbackCopyFile* cb, //may be nullptr
+ const Zstring& sourceFile,
+ const Zstring& targetFile) :
+ sourceFile_(sourceFile),
+ targetFile_(targetFile),
+ userCallback(cb) {}
+
+ const Zstring& sourceFile_;
+ const Zstring& targetFile_;
- FileAttrib newAttrib;
- std::wstring errorMsg; //
- bool exceptionInUserCallback; //these two are exclusive!
- UInt64 bytesTransferredOnException;
+ CallbackCopyFile* const userCallback; //optional!
+ ErrorHandling errorHandler;
+ FileAttrib newAttrib; //modified by CopyFileEx at start
};
@@ -1541,42 +1915,34 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
if (dwCallbackReason == CALLBACK_STREAM_SWITCH && //called up-front for every file (even if 0-sized)
dwStreamNumber == 1) //consider ADS!
{
+ if (canCopyAsSparse(hSourceFile, cbd.targetFile_)) //throw ()
+ {
+ cbd.errorHandler.reportErrorShouldCopyAsSparse(); //use another copy routine!
+ return PROGRESS_CANCEL;
+ }
+
//#################### return source file attributes ################################
BY_HANDLE_FILE_INFORMATION fileInfoSrc = {};
if (!::GetFileInformationByHandle(hSourceFile, &fileInfoSrc))
{
- cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.sourceFile_ + L"\"" + L"\n\n" + getLastErrorFormatted());
+ cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.sourceFile_)) + L"\n\n" + getLastErrorFormatted());
return PROGRESS_CANCEL;
}
BY_HANDLE_FILE_INFORMATION fileInfoTrg = {};
if (!::GetFileInformationByHandle(hDestinationFile, &fileInfoTrg))
{
- cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.targetFile_ + L"\"" + L"\n\n" + getLastErrorFormatted());
+ cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.targetFile_)) + L"\n\n" + getLastErrorFormatted());
return PROGRESS_CANCEL;
}
- FileAttrib attr;
- attr.fileSize = UInt64(fileInfoSrc.nFileSizeLow, fileInfoSrc.nFileSizeHigh);
- attr.modificationTime = toTimeT(fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
- attr.sourceFileId = extractFileID(fileInfoSrc);
- attr.targetFileId = extractFileID(fileInfoTrg);
-
- cbd.setNewAttr(attr);
+ cbd.newAttrib.fileSize = UInt64(fileInfoSrc.nFileSizeLow, fileInfoSrc.nFileSizeHigh);
+ cbd.newAttrib.modificationTime = toTimeT(fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
+ cbd.newAttrib.sourceFileId = extractFileID(fileInfoSrc);
+ cbd.newAttrib.targetFileId = extractFileID(fileInfoTrg);
//#################### copy file creation time ################################
- FILETIME creationTime = {};
-
- if (!::GetFileTime(hSourceFile, //__in HANDLE hFile,
- &creationTime, //__out_opt LPFILETIME lpCreationTime,
- nullptr, //__out_opt LPFILETIME lpLastAccessTime,
- nullptr)) //__out_opt LPFILETIME lpLastWriteTime
- {
- cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.sourceFile_ + L"\"" + L"\n\n" + getLastErrorFormatted());
- return PROGRESS_CANCEL;
- }
-
- ::SetFileTime(hDestinationFile, &creationTime, nullptr, nullptr); //no error handling!
+ ::SetFileTime(hDestinationFile, &fileInfoSrc.ftCreationTime, nullptr, nullptr); //no error handling!
//##############################################################################
}
@@ -1594,13 +1960,13 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
nullptr, 0);
try
{
- cbd.userCallback->updateCopyStatus(UInt64(totalBytesTransferred.QuadPart));
+ cbd.userCallback->updateCopyStatus(UInt64(totalBytesTransferred.QuadPart)); //throw X!
}
catch (...)
{
//#warning migrate to std::exception_ptr when available
- cbd.reportUserException(UInt64(totalBytesTransferred.QuadPart));
+ cbd.errorHandler.reportUserException(*cbd.userCallback, UInt64(totalBytesTransferred.QuadPart));
return PROGRESS_CANCEL;
}
}
@@ -1608,56 +1974,68 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
}
-#ifndef COPY_FILE_ALLOW_DECRYPTED_DESTINATION
-#define COPY_FILE_ALLOW_DECRYPTED_DESTINATION 0x00000008
-#endif
+const bool supportNonEncryptedDestination = winXpOrLater(); //encrypted destination is not supported with Windows 2000
+const bool supportUnbufferedCopy = vistaOrLater();
+//caveat: function scope static initialization is not thread-safe in VS 2010!
-void rawCopyWinApi_sub(const Zstring& sourceFile,
- const Zstring& targetFile,
- CallbackCopyFile* callback,
- FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+
+void copyFileWindowsDefault(const Zstring& sourceFile,
+ const Zstring& targetFile,
+ CallbackCopyFile* callback,
+ FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked, ErrorShouldCopyAsSparse
{
zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (...) {} });
//transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we? ;)
DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS;
- //allow copying from encrypted to non-encrytped location
- static bool nonEncSupported = false;
- {
- static boost::once_flag initNonEncOnce = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010!
- boost::call_once(initNonEncOnce, [] { nonEncSupported = winXpOrLater(); }); //encrypted destination is not supported with Windows 2000
- }
- if (nonEncSupported)
- copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION;
+#ifndef COPY_FILE_ALLOW_DECRYPTED_DESTINATION
+ const DWORD COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008;
+#endif
+
+ if (supportNonEncryptedDestination)
+ copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; //allow copying from encrypted to non-encrytped location
+
+ if (supportUnbufferedCopy) //see http://blogs.technet.com/b/askperf/archive/2007/05/08/slow-large-file-copy-issues.aspx
+ copyFlags |= COPY_FILE_NO_BUFFERING; //no perf difference at worst, huge improvement for large files (20% in test NTFS -> NTFS)
CallbackData cbd(callback, sourceFile, targetFile);
const bool success = ::CopyFileEx( //same performance like CopyFile()
- applyLongPathPrefix(sourceFile).c_str(),
- applyLongPathPrefix(targetFile).c_str(),
- copyCallbackInternal,
- &cbd,
- nullptr,
- copyFlags) == TRUE; //silence x64 perf warning
-
- cbd.evaluateErrors(); //throw ?, process errors in callback first!
+ applyLongPathPrefix(sourceFile).c_str(), //__in LPCTSTR lpExistingFileName,
+ applyLongPathPrefix(targetFile).c_str(), //__in LPCTSTR lpNewFileName,
+ copyCallbackInternal, //__in_opt LPPROGRESS_ROUTINE lpProgressRoutine,
+ &cbd, //__in_opt LPVOID lpData,
+ nullptr, //__in_opt LPBOOL pbCancel,
+ copyFlags) == TRUE; //__in DWORD dwCopyFlags
+
+ cbd.errorHandler.evaluateErrors(); //throw ?, process errors in callback first!
if (!success)
{
const DWORD lastError = ::GetLastError();
//don't suppress "lastError == ERROR_REQUEST_ABORTED": a user aborted operation IS an error condition!
+ //trying to copy huge sparse files may fail with ERROR_DISK_FULL
+ if (canCopyAsSparse(sourceFile, targetFile)) //throw ()
+ throw ErrorShouldCopyAsSparse(L"sparse dummy value2");
+
//assemble error message...
- std::wstring errorMessage = _("Error copying file:") + L"\n\"" + sourceFile + L"\" ->\n\"" + targetFile + L"\"" +
+ std::wstring errorMessage = replaceCpy(replaceCpy(_("Cannot copy file %x to %y."), L"%x", fmtFileName(sourceFile)), L"%y", fmtFileName(targetFile)) +
L"\n\n" + getLastErrorFormatted(lastError);
- //if file is locked (try to) use Windows Volume Shadow Copy Service
+ //if file is locked throw "ErrorFileLocked" instead!
if (lastError == ERROR_SHARING_VIOLATION ||
lastError == ERROR_LOCK_VIOLATION)
- throw ErrorFileLocked(errorMessage);
+ {
+ const Zstring procList = getLockingProcessNames(sourceFile); //throw() -> enhance error message!
+ throw ErrorFileLocked(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" +
+ (!procList.empty() ? _("The file is locked by another process:") + L"\n" + procList : getLastErrorFormatted(lastError)));
+ }
- if (lastError == ERROR_FILE_EXISTS) //if target is existing this functions is expected to throw ErrorTargetExisting!!!
+ //if target is existing this functions is expected to throw ErrorTargetExisting!!!
+ if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
+ lastError == ERROR_ALREADY_EXISTS) //not sure if used -> better be safe than sorry!!!
{
guardTarget.dismiss(); //don't delete file that existed previously!
throw ErrorTargetExisting(errorMessage);
@@ -1685,7 +2063,7 @@ void rawCopyWinApi_sub(const Zstring& sourceFile,
}
if (newAttrib)
- *newAttrib = cbd.getSrcAttr();
+ *newAttrib = cbd.newAttrib;
{
//DST hack
@@ -1703,358 +2081,44 @@ void rawCopyWinApi_sub(const Zstring& sourceFile,
}
+//another layer to support copying sparse files
inline
-void rawCopyWinApi(const Zstring& sourceFile,
- const Zstring& targetFile,
- CallbackCopyFile* callback,
- FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, FileAttrib* sourceAttr)
{
try
{
- rawCopyWinApi_sub(sourceFile, targetFile, callback, sourceAttr); // throw ...
+ copyFileWindowsDefault(sourceFile, targetFile, callback, sourceAttr); //throw ErrorShouldCopyAsSparse et al.
}
- catch (ErrorTargetExisting&)
+ catch (ErrorShouldCopyAsSparse&) //we cheaply check for this condition within callback of ::CopyFileEx()!
+ {
+ copyFileWindowsSparse(sourceFile, targetFile, callback, sourceAttr);
+ }
+}
+
+
+//another layer of indirection solving 8.3 name clashes
+inline
+void copyFileWindows(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, FileAttrib* sourceAttr)
+{
+ try
+ {
+ copyFileWindowsSelectRoutine(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+ }
+ catch (const ErrorTargetExisting&)
{
//try to handle issues with already existing short 8.3 file names on Windows
if (have8dot3NameClash(targetFile))
{
Fix8Dot3NameClash dummy(targetFile); //move clashing filename to the side
- rawCopyWinApi_sub(sourceFile, targetFile, callback, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now
+ copyFileWindowsSelectRoutine(sourceFile, targetFile, callback, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now
return;
}
throw;
}
}
-//void rawCopyWinOptimized(const Zstring& sourceFile,
-// const Zstring& targetFile,
-// CallbackCopyFile* callback) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
-//{
-// /*
-// BackupRead() FileRead() CopyFileEx()
-// --------------------------------------------
-// Attributes NO NO YES
-// create time NO NO NO
-// ADS YES NO YES
-// Encrypted NO(silent fail) NO YES
-// Compressed NO NO NO
-// Sparse YES NO NO
-// PERF 6% faster -
-//
-// Mark stream as compressed: FSCTL_SET_COMPRESSION
-// compatible with: BackupRead() FileRead()
-// */
-//
-//FILE_FLAG_BACKUP_SEMANTICS ??????
-//
-// //open sourceFile for reading
-// HANDLE hFileIn = ::CreateFile(applyLongPathPrefix(sourceFile).c_str(),
-// GENERIC_READ,
-// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read files that are open in other applications
-// nullptr,
-// OPEN_EXISTING,
-// FILE_FLAG_SEQUENTIAL_SCAN,
-// nullptr);
-// if (hFileIn == INVALID_HANDLE_VALUE)
-// {
-// const DWORD lastError = ::GetLastError();
-// const std::wstring& errorMessage = Error opening file: + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted(lastError);
-//
-// //if file is locked (try to) use Windows Volume Shadow Copy Service
-// if (lastError == ERROR_SHARING_VIOLATION ||
-// lastError == ERROR_LOCK_VIOLATION)
-// throw ErrorFileLocked(errorMessage);
-//
-// throw FileError(errorMessage);
-// }
-// ZEN_ON_SCOPE_EXIT(::CloseHandle, hFileIn);
-//
-//
-// BY_HANDLE_FILE_INFORMATION infoFileIn = {};
-// if (!::GetFileInformationByHandle(hFileIn, &infoFileIn))
-// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
-//
-// //####################################### DST hack ###########################################
-// if (dst::isFatDrive(sourceFile)) //throw()
-// {
-// const dst::RawTime rawTime(infoFileIn.ftCreationTime, infoFileIn.ftLastWriteTime);
-// if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error)
-// {
-// infoFileIn.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return last write time in real UTC, throw (std::runtime_error)
-// ::GetSystemTimeAsFileTime(&infoFileIn.ftCreationTime); //real creation time information is not available...
-// }
-// }
-//
-// if (dst::isFatDrive(targetFile)) //throw()
-// {
-// const dst::RawTime encodedTime = dst::fatEncodeUtcTime(infoFileIn.ftLastWriteTime); //throw (std::runtime_error)
-// infoFileIn.ftCreationTime = encodedTime.createTimeRaw;
-// infoFileIn.ftLastWriteTime = encodedTime.writeTimeRaw;
-// }
-// //####################################### DST hack ###########################################
-//
-// const DWORD validAttribs = FILE_ATTRIBUTE_READONLY |
-// FILE_ATTRIBUTE_HIDDEN |
-// FILE_ATTRIBUTE_SYSTEM |
-// FILE_ATTRIBUTE_ARCHIVE | //those two are not set properly (not worse than ::CopyFileEx())
-// FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | //
-// FILE_ATTRIBUTE_ENCRYPTED;
-//
-// //create targetFile and open it for writing
-// HANDLE hFileOut = ::CreateFile(applyLongPathPrefix(targetFile).c_str(),
-// GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
-// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-// nullptr,
-// CREATE_NEW,
-// (infoFileIn.dwFileAttributes & validAttribs) | FILE_FLAG_SEQUENTIAL_SCAN,
-// nullptr);
-// if (hFileOut == INVALID_HANDLE_VALUE)
-// {
-// const DWORD lastError = ::GetLastError();
-// const std::wstring& errorMessage =
-//
-// if (lastError == ERROR_FILE_EXISTS)
-// throw ErrorTargetExisting(errorMessage);
-//
-// if (lastError == ERROR_PATH_NOT_FOUND)
-// throw ErrorTargetPathMissing(errorMessage);
-//
-// throw FileError(errorMessage);
-// }
-// Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: guard just after opening target and before managing hFileOut
-//
-// ZEN_ON_SCOPE_EXIT(::CloseHandle, hFileOut);
-//
-//
-//#ifndef _MSC_VER
-//#warning teste perf von GetVolumeInformationByHandleW
-//#endif
-// DWORD fsFlags = 0;
-// if (!GetVolumeInformationByHandleW(hFileOut, //__in HANDLE hFile,
-// nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
-// 0, //__in DWORD nVolumeNameSize,
-// nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
-// nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
-// &fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
-// nullptr, //__out LPTSTR lpFileSystemNameBuffer,
-// 0)) //__in DWORD nFileSystemNameSize
-// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
-//
-// const bool sourceIsEncrypted = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
-// const bool sourceIsCompressed = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
-// const bool sourceIsSparse = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0;
-//
-// bool targetSupportSparse = (fsFlags & FILE_SUPPORTS_SPARSE_FILES) != 0;
-// bool targetSupportCompressed = (fsFlags & FILE_FILE_COMPRESSION ) != 0;
-// bool targetSupportStreams = (fsFlags & FILE_NAMED_STREAMS ) != 0;
-//
-//
-// const bool useBackupFun = !sourceIsEncrypted; //http://msdn.microsoft.com/en-us/library/aa362509(v=VS.85).aspx
-//
-// if (sourceIsCompressed && targetSupportCompressed)
-// {
-// USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
-//
-// DWORD bytesReturned = 0;
-// if (!DeviceIoControl(hFileOut, //handle to file or directory
-// FSCTL_SET_COMPRESSION, //dwIoControlCode
-// &cmpState, //input buffer
-// sizeof(cmpState), //size of input buffer
-// nullptr, //lpOutBuffer
-// 0, //OutBufferSize
-// &bytesReturned, //number of bytes returned
-// nullptr)) //OVERLAPPED structure
-// throw FileError( ddd +
-// "\nFailed to write NTFS compressed attribute!");
-// }
-//
-// //although it seems the sparse attribute is set automatically by BackupWrite, we are required to do this manually: http://support.microsoft.com/kb/271398/en-us
-// if (sourceIsSparse && targetSupportSparse)
-// {
-// if (useBackupFun)
-// {
-// DWORD bytesReturned = 0;
-// if (!DeviceIoControl(hFileOut, //handle to file
-// FSCTL_SET_SPARSE, //dwIoControlCode
-// nullptr, //input buffer
-// 0, //size of input buffer
-// nullptr, //lpOutBuffer
-// 0, //OutBufferSize
-// &bytesReturned, //number of bytes returned
-// nullptr)) //OVERLAPPED structure
-// throw FileError(dddd
-// "\nFailed to write NTFS sparse attribute!");
-// }
-// }
-//
-//
-// const DWORD BUFFER_SIZE = 512 * 1024; //512 kb seems to be a reasonable buffer size
-// static boost::thread_specific_ptr<std::vector<char>> cpyBuf;
-// if (!cpyBuf.get())
-// cpyBuf.reset(new std::vector<char>(BUFFER_SIZE)); //512 kb seems to be a reasonable buffer size
-// std::vector<char>& buffer = *cpyBuf;
-//
-// struct ManageCtxt //manage context for BackupRead()/BackupWrite()
-// {
-// ManageCtxt() : read(nullptr), write(nullptr) {}
-// ~ManageCtxt()
-// {
-// if (read != nullptr)
-// ::BackupRead (0, nullptr, 0, nullptr, true, false, &read);
-// if (write != nullptr)
-// ::BackupWrite(0, nullptr, 0, nullptr, true, false, &write);
-// }
-//
-// LPVOID read;
-// LPVOID write;
-// } context;
-//
-// //copy contents of sourceFile to targetFile
-// UInt64 totalBytesTransferred;
-//
-// bool eof = false;
-// do
-// {
-// DWORD bytesRead = 0;
-//
-// if (useBackupFun)
-// {
-// if (!::BackupRead(hFileIn, //__in HANDLE hFile,
-// &buffer[0], //__out LPBYTE lpBuffer,
-// BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead,
-// &bytesRead, //__out LPDWORD lpNumberOfBytesRead,
-// false, //__in BOOL bAbort,
-// false, //__in BOOL bProcessSecurity,
-// &context.read)) //__out LPVOID *lpContext
-// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
-// "\n\n" + getLastErrorFormatted());
-// }
-// else if (!::ReadFile(hFileIn, //__in HANDLE hFile,
-// &buffer[0], //__out LPVOID lpBuffer,
-// BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead,
-// &bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
-// nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
-// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
-// "\n\n" + getLastErrorFormatted());
-//
-// if (bytesRead > BUFFER_SIZE)
-// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
-// "\n\n" + "buffer overflow");
-//
-// if (bytesRead < BUFFER_SIZE)
-// eof = true;
-//
-// DWORD bytesWritten = 0;
-//
-// if (useBackupFun)
-// {
-// if (!::BackupWrite(hFileOut, //__in HANDLE hFile,
-// &buffer[0], //__in LPBYTE lpBuffer,
-// bytesRead, //__in DWORD nNumberOfBytesToWrite,
-// &bytesWritten, //__out LPDWORD lpNumberOfBytesWritten,
-// false, //__in BOOL bAbort,
-// false, //__in BOOL bProcessSecurity,
-// &context.write)) //__out LPVOID *lpContext
-// throw FileError(ddd" (w)"); //w -> distinguish from fopen error message!
-// }
-// else if (!::WriteFile(hFileOut, //__in HANDLE hFile,
-// &buffer[0], //__out LPVOID lpBuffer,
-// bytesRead, //__in DWORD nNumberOfBytesToWrite,
-// &bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
-// nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
-// throw FileError(ddd" (w)"); //w -> distinguish from fopen error message!
-//
-// if (bytesWritten != bytesRead)
-// throw FileError(ddd + "incomplete write");
-//
-// totalBytesTransferred += bytesRead;
-//
-//#ifndef _MSC_VER
-//#warning totalBytesTransferred kann größer als filesize sein!!
-//#endif
-//
-// //invoke callback method to update progress indicators
-// if (callback != nullptr)
-// switch (callback->updateCopyStatus(totalBytesTransferred))
-// {
-// case CallbackCopyFile::CONTINUE:
-// break;
-//
-// case CallbackCopyFile::CANCEL: //a user aborted operation IS an error condition!
-// throw FileError(Error copying file:") + "\n\"" + sourceFile + "\" ->\n\"" +
-// targetFile + "\"\n\n" + Operation aborted!"));
-// }
-// }
-// while (!eof);
-//
-//
-// if (totalBytesTransferred == 0) //BackupRead silently fails reading encrypted files -> double check!
-// {
-// LARGE_INTEGER inputSize = {};
-// if (!::GetFileSizeEx(hFileIn, &inputSize))
-// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
-//
-// if (inputSize.QuadPart != 0)
-// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" + "\n\n" + "unknown error");
-// }
-//
-// //time needs to be set at the end: BackupWrite() changes file time
-// if (!::SetFileTime(hFileOut,
-// &infoFileIn.ftCreationTime,
-// nullptr,
-// &infoFileIn.ftLastWriteTime))
-// throw FileError(Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + getLastErrorFormatted());
-//
-//
-//#ifndef NDEBUG //dst hack: verify data written
-// if (dst::isFatDrive(targetFile)) //throw()
-// {
-// WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {};
-// assert(::GetFileAttributesEx(applyLongPathPrefix(targetFile).c_str(), //__in LPCTSTR lpFileName,
-// GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId,
-// &debugeAttr)); //__out LPVOID lpFileInformation
-//
-// assert(::CompareFileTime(&debugeAttr.ftCreationTime, &infoFileIn.ftCreationTime) == 0);
-// assert(::CompareFileTime(&debugeAttr.ftLastWriteTime, &infoFileIn.ftLastWriteTime) == 0);
-// }
-//#endif
-//
-// guardTarget.Dismiss();
-//
-// /*
-// //create test sparse file
-// HANDLE hSparse = ::CreateFile(L"C:\\sparse.file",
-// GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
-// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-// 0,
-// CREATE_NEW,
-// FILE_FLAG_SEQUENTIAL_SCAN,
-// nullptr);
-// DWORD br = 0;
-// if (!::DeviceIoControl(hSparse, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &br,nullptr))
-// throw 1;
-//
-// LARGE_INTEGER liDistanceToMove = {};
-// liDistanceToMove.QuadPart = 1024 * 1024 * 1024; //create 5 TB sparse file
-// liDistanceToMove.QuadPart *= 5 * 1024; //
-// if (!::SetFilePointerEx(hSparse, liDistanceToMove, nullptr, FILE_BEGIN))
-// throw 1;
-//
-// if (!SetEndOfFile(hSparse))
-// throw 1;
-//
-// FILE_ZERO_DATA_INFORMATION zeroInfo = {};
-// zeroInfo.BeyondFinalZero.QuadPart = liDistanceToMove.QuadPart;
-// if (!::DeviceIoControl(hSparse, FSCTL_SET_ZERO_DATA, &zeroInfo, sizeof(zeroInfo), nullptr, 0, &br, nullptr))
-// throw 1;
-//
-// ::CloseHandle(hSparse);
-// */
-//}
-#endif
-
-#ifdef FFS_LINUX
-void rawCopyStream(const Zstring& sourceFile,
+#elif defined FFS_LINUX
+void copyFileLinux(const Zstring& sourceFile,
const Zstring& targetFile,
CallbackCopyFile* callback,
FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting
@@ -2088,7 +2152,7 @@ void rawCopyStream(const Zstring& sourceFile,
//invoke callback method to update progress indicators
if (callback)
- callback->updateCopyStatus(totalBytesTransferred);
+ callback->updateCopyStatus(totalBytesTransferred); //throw X!
}
while (!fileIn.eof());
}
@@ -2102,7 +2166,7 @@ void rawCopyStream(const Zstring& sourceFile,
{
struct ::stat srcInfo = {};
if (::stat(sourceFile.c_str(), &srcInfo) != 0) //read file attributes from source directory
- throw FileError(_("Error reading file attributes:") + L"\n\"" + sourceFile + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)) + L"\n\n" + getLastErrorFormatted());
struct ::utimbuf newTimes = {};
newTimes.actime = srcInfo.st_atime;
@@ -2110,13 +2174,13 @@ void rawCopyStream(const Zstring& sourceFile,
//set new "last write time"
if (::utime(targetFile.c_str(), &newTimes) != 0)
- throw FileError(_("Error changing modification time:") + L"\n\"" + targetFile + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
if (newAttrib)
{
struct ::stat trgInfo = {};
if (::stat(targetFile.c_str(), &trgInfo) != 0) //read file attributes from source directory
- throw FileError(_("Error reading file attributes:") + L"\n\"" + targetFile + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)) + L"\n\n" + getLastErrorFormatted());
newAttrib->fileSize = UInt64(srcInfo.st_size);
newAttrib->modificationTime = srcInfo.st_mtime;
@@ -2130,31 +2194,41 @@ void rawCopyStream(const Zstring& sourceFile,
#endif
+Zstring createTempName(const Zstring& filename)
+{
+ Zstring output = filename + zen::TEMP_FILE_ENDING;
+
+ //ensure uniqueness
+ for (int i = 1; somethingExists(output); ++i)
+ output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
+
+ return output;
+}
+
+
+/*
+ File Copy Layers
+ ================
+
+ copyFile (setup transactional behavior)
+ |
+ copyFileSelectOs
+ / \
+copyFileLinux copyFileWindows (solve 8.3 issue)
+ |
+ copyFileWindowsSelectRoutine
+ / \
+copyFileWindowsDefault(::CopyFileEx) copyFileWindowsSparse(::BackupRead/::BackupWrite)
+*/
+
inline
-void copyFileImpl(const Zstring& sourceFile,
- const Zstring& targetFile,
- CallbackCopyFile* callback,
- FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+void copyFileSelectOs(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, FileAttrib* sourceAttr)
{
#ifdef FFS_WIN
- /*
- rawCopyWinApi() rawCopyWinOptimized()
- -------------------------------------
- Attributes YES YES
- Filetimes YES YES
- ADS YES YES
- Encrypted YES YES
- Compressed NO YES
- Sparse NO YES
- PERF - 6% faster
- SAMBA, ect. YES UNKNOWN! -> issues writing ADS to Samba, issues reading from NAS, error copying files having "blocked" state... ect. damn!
- */
-
- rawCopyWinApi(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
- //rawCopyWinOptimized(sourceFile, targetFile, callback); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked ->about 8% faster
+ copyFileWindows(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
#elif defined FFS_LINUX
- rawCopyStream(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting
+ copyFileLinux(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting
#endif
}
}
@@ -2170,12 +2244,12 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
if (transactionalCopy)
{
Zstring temporary = targetFile + zen::TEMP_FILE_ENDING; //use temporary file until a correct date has been set
- zen::ScopeGuard guardTempFile = zen::makeGuard([&]() { removeFile(temporary); }); //transactional behavior: ensure cleanup (e.g. network drop) -> ref to temporary[!]
+ zen::ScopeGuard guardTempFile = zen::makeGuard([&] { try { removeFile(temporary); } catch (...) {} }); //transactional behavior: ensure cleanup (e.g. network drop) -> ref to temporary[!]
//raw file copy
try
{
- copyFileImpl(sourceFile, temporary, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+ copyFileSelectOs(sourceFile, temporary, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
}
catch (ErrorTargetExisting&)
{
@@ -2184,7 +2258,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
temporary = createTempName(targetFile);
//retry
- copyFileImpl(sourceFile, temporary, callback, sourceAttr); //throw FileError
+ copyFileSelectOs(sourceFile, temporary, callback, sourceAttr); //throw FileError
}
//have target file deleted (after read access on source and target has been confirmed) => allow for almost transactional overwrite
@@ -2202,7 +2276,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
//have target file deleted
if (callback) callback->deleteTargetFile(targetFile);
- copyFileImpl(sourceFile, targetFile, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
+ copyFileSelectOs(sourceFile, targetFile, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
}
/*
Note: non-transactional file copy solves at least four problems:
@@ -2215,7 +2289,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
//file permissions
if (copyFilePermissions)
{
- zen::ScopeGuard guardTargetFile = zen::makeGuard([&] { removeFile(targetFile);});
+ zen::ScopeGuard guardTargetFile = zen::makeGuard([&] { try { removeFile(targetFile); } catch (...) {}});
copyObjectPermissions(sourceFile, targetFile, SYMLINK_FOLLOW); //throw FileError
diff --git a/zen/file_handling.h b/zen/file_handling.h
index b0d97a6c..e90ad544 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -45,6 +45,7 @@ void setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSym
//symlink handling: always evaluate target
UInt64 getFilesize(const Zstring& filename); //throw FileError
+UInt64 getFreeDiskSpace(const Zstring& path); //throw FileError
//file handling
bool removeFile(const Zstring& filename); //return "true" if file was actually deleted; throw FileError
@@ -54,13 +55,10 @@ void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nul
//rename file or directory: no copying!!!
void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError;
-//move source to target; expectations: all super-directories of target exist
-//"ignoreExisting": if target already exists, source is deleted
-void moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback); //throw FileError;
-
-//move source to target including subdirectories
-//"ignoreExisting": existing directories and files will be enriched
-void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback); //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
bool supportsPermissions(const Zstring& dirname); //throw FileError, derefernces symlinks
@@ -109,7 +107,7 @@ struct CallbackCopyFile //callback functionality
//may throw:
//Linux: unconditionally
- //Windows: first exception is swallowed, requestUiRefresh() is then called again where it should throw again and exception will propagate as expected
+ //Windows: first exception is swallowed, updateCopyStatus() is then called again where it should throw again and exception will propagate as expected
virtual void updateCopyStatus(UInt64 totalBytesTransferred) = 0;
};
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 4c38bb22..462364da 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -27,7 +27,7 @@ FileInput::FileInput(const Zstring& filename) : //throw FileError, ErrorNotExis
fileHandle = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read open files that are shared by other applications
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
/* possible values: (Reference http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx#caching_behavior)
@@ -62,7 +62,7 @@ FileInput::FileInput(const Zstring& filename) : //throw FileError, ErrorNotExis
#endif
{
const ErrorCode lastError = getLastError();
- std::wstring errorMessage = _("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError) + L" (open)";
+ std::wstring errorMessage = replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + getLastErrorFormatted(lastError) + L" (open)";
if (errorCodeForNotExisting(lastError))
throw ErrorNotExisting(errorMessage);
@@ -95,7 +95,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number
const size_t bytesRead = ::fread(buffer, 1, bytesToRead, fileHandle);
if (::ferror(fileHandle) != 0)
#endif
- throw FileError(_("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted() + L" (read)");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + getLastErrorFormatted() + L" (read)");
#ifdef FFS_WIN
if (bytesRead < bytesToRead) //verify only!
@@ -105,7 +105,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number
eofReached = true;
if (bytesRead > bytesToRead)
- throw FileError(_("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + L"buffer overflow");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + L"buffer overflow");
return bytesRead;
}
@@ -132,16 +132,17 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
The resulting code is faster, because the redirector can use the cache manager and send fewer SMBs with more data.
This combination also avoids an issue where writing to a file across a network can occasionally return ERROR_ACCESS_DENIED. */
FILE_SHARE_READ | FILE_SHARE_DELETE, //note: FILE_SHARE_DELETE is required to rename file while handle is open!
- 0,
+ nullptr,
access == ACC_OVERWRITE ? CREATE_ALWAYS : CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
{
const DWORD lastError = ::GetLastError();
- std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted(lastError);
+ const std::wstring errorMessage = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + zen::getLastErrorFormatted(lastError);
- if (lastError == ERROR_FILE_EXISTS)
+ if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
+ lastError == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
throw ErrorTargetExisting(errorMessage);
if (lastError == ERROR_PATH_NOT_FOUND)
@@ -157,7 +158,7 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
if (!fileHandle)
{
const int lastError = errno;
- std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted(lastError);
+ const std::wstring errorMessage = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + zen::getLastErrorFormatted(lastError);
if (lastError == EEXIST)
throw ErrorTargetExisting(errorMessage);
@@ -193,8 +194,8 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
const size_t bytesWritten = ::fwrite(buffer, 1, bytesToWrite, fileHandle);
if (::ferror(fileHandle) != 0)
#endif
- throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted() + L" (w)"); //w -> distinguish from fopen error message!
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + getLastErrorFormatted() + L" (w)"); //w -> distinguish from fopen error message!
if (bytesWritten != bytesToWrite) //must be fulfilled for synchronous writes!
- throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + L"incomplete write");
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename_)) + L"\n\n" + L"(incomplete write)");
}
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index c3536825..ea6aa289 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -63,7 +63,7 @@ bool extractFileInfoFromSymlink(const Zstring& linkName, zen::TraverseCallback::
HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(linkName).c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
@@ -76,7 +76,7 @@ bool extractFileInfoFromSymlink(const Zstring& linkName, zen::TraverseCallback::
return false;
//write output
- output.fileSize = zen::UInt64(fileInfoByHandle.nFileSizeLow, fileInfoByHandle.nFileSizeHigh);
+ output.fileSize = UInt64(fileInfoByHandle.nFileSizeLow, fileInfoByHandle.nFileSizeHigh);
output.lastWriteTimeRaw = toTimeT(fileInfoByHandle.ftLastWriteTime);
output.id = FileId(); //= extractFileID(fileInfoByHandle); -> id from dereferenced symlink is problematic, since renaming will consider the link, not the target!
return true;
@@ -91,16 +91,6 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error or if s
//- indirection: subst S: %USERPROFILE%
// -> GetVolumePathName() on the other hand resolves "S:\Desktop\somedir" to "S:\Desktop\" - nice try...
- typedef BOOL (WINAPI* GetFileInformationByHandleFunc)(HANDLE hFile,
- LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
-
- const SysDllFun<GetFileInformationByHandleFunc> getFileInformationByHandle(L"kernel32.dll", "GetFileInformationByHandle"); //available since Windows XP
- if (!getFileInformationByHandle)
- {
- assert(false);
- return 0;
- }
-
const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(pathName).c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -113,8 +103,7 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error or if s
ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
BY_HANDLE_FILE_INFORMATION fileInfo = {};
- if (!getFileInformationByHandle(hDir, //__in HANDLE hFile,
- &fileInfo)) //__out LPBY_HANDLE_FILE_INFORMATION lpFileInformation
+ if (!::GetFileInformationByHandle(hDir, &fileInfo))
return 0;
return fileInfo.dwVolumeSerialNumber;
@@ -135,18 +124,16 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error!
BUFFER_SIZE)) //__in DWORD cchBufferLength
return 0;
- Zstring volumePath = &buffer[0];
- if (!endsWith(volumePath, FILE_NAME_SEPARATOR))
- volumePath += FILE_NAME_SEPARATOR;
+ Zstring volumePath = appendSeparator(&buffer[0]);
DWORD volumeSerial = 0;
if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
- nullptr, //__out LPTSTR lpVolumeNameBuffer,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
0, //__in DWORD nVolumeNameSize,
&volumeSerial, //__out_opt LPDWORD lpVolumeSerialNumber,
- nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
- nullptr, //__out_opt LPDWORD lpFileSystemFlags,
- nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
return 0;
@@ -157,9 +144,9 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error!
const bool isXpOrLater = winXpOrLater(); //VS2010 compiled DLLs are not supported on Win 2000: Popup dialog "DecodePointer not found"
-const DllFun<findplus::OpenDirFunc> openDir = isXpOrLater ? DllFun<findplus::OpenDirFunc >(findplus::getDllName(), findplus::openDirFuncName ) : DllFun<findplus::OpenDirFunc >(); //
-const DllFun<findplus::ReadDirFunc> readDir = isXpOrLater ? DllFun<findplus::ReadDirFunc >(findplus::getDllName(), findplus::readDirFuncName ) : DllFun<findplus::ReadDirFunc >(); //load at startup: avoid pre C++11 static initialization MT issues
-const DllFun<findplus::CloseDirFunc> closeDir= isXpOrLater ? DllFun<findplus::CloseDirFunc>(findplus::getDllName(), findplus::closeDirFuncName) : DllFun<findplus::CloseDirFunc>(); //
+const auto openDir = isXpOrLater ? DllFun<findplus::FunType_openDir >(findplus::getDllName(), findplus::funName_openDir ) : DllFun<findplus::FunType_openDir >(); //
+const auto readDir = isXpOrLater ? DllFun<findplus::FunType_readDir >(findplus::getDllName(), findplus::funName_readDir ) : DllFun<findplus::FunType_readDir >(); //load at startup: avoid pre C++11 static initialization MT issues
+const auto closeDir= isXpOrLater ? DllFun<findplus::FunType_closeDir>(findplus::getDllName(), findplus::funName_closeDir) : DllFun<findplus::FunType_closeDir>(); //
/*
Common C-style interface for Win32 FindFirstFile(), FindNextFile() and FileFilePlus openDir(), closeDir():
@@ -203,21 +190,17 @@ struct Win32Traverser
static void create(const Zstring& directory, DirHandle& hnd) //throw FileError
{
- const Zstring& directoryPf = endsWith(directory, FILE_NAME_SEPARATOR) ?
- directory :
- directory + FILE_NAME_SEPARATOR;
+ const Zstring& directoryPf = appendSeparator(directory);
hnd.searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &hnd.firstData);
//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(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
//::GetLastError() == ERROR_FILE_NOT_FOUND -> *usually* NOT okay:
- //however it is unclear whether this indicates a missing directory or a completely empty directory
- // note: not all directories contain "., .." entries! E.g. a drive's root directory or NetDrive + ftp.gnu.org\CRYPTO.README"
- // -> addon: this is NOT a directory, it looks like one in NetDrive, but it's a file in Opera!
- //we have to guess it's former and let the error propagate
- // -> FindFirstFile() is a nice example of violation of API design principle of single responsibility and its consequences
+ //directory may not exist *or* it is completely empty: not all directories contain "., .." entries, e.g. a drive's root directory
+ //usually a directory is never completely empty due to "sync.ffs_lock", so we assume it's not existing and let the error propagate
+ // -> FindFirstFile() is a nice example of violation of API design principle of single responsibility
}
static void destroy(const DirHandle& hnd) { ::FindClose(hnd.searchHandle); } //throw()
@@ -237,7 +220,7 @@ struct Win32Traverser
if (::GetLastError() == ERROR_NO_MORE_FILES) //not an error situation
return false;
//else we have a problem... report it:
- throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}
return true;
}
@@ -285,7 +268,7 @@ struct FilePlusTraverser
{
hnd.searchHandle = ::openDir(applyLongPathPrefix(directory).c_str());
if (hnd.searchHandle == nullptr)
- throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}
static void destroy(DirHandle hnd) { ::closeDir(hnd.searchHandle); } //throw()
@@ -304,7 +287,7 @@ struct FilePlusTraverser
this is required for NetDrive mounted Webdav, e.g. www.box.net and NT4, 2000 remote drives, et al.
NT status code | Win32 error code
- -----------------------------------------------------------
+ --------------------------------|--------------------------
STATUS_INVALID_LEVEL | ERROR_INVALID_LEVEL
STATUS_NOT_SUPPORTED | ERROR_NOT_SUPPORTED
STATUS_INVALID_PARAMETER | ERROR_INVALID_PARAMETER
@@ -327,7 +310,7 @@ struct FilePlusTraverser
}
//else we have a problem... report it:
- throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}
return true;
}
@@ -394,7 +377,7 @@ private:
tryReportingError([&]
{
if (level == 100) //notify endless recursion
- throw FileError(_("Endless loop when traversing directory:") + L"\n\"" + directory + L"\"");
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + _("Endless loop."));
}, sink);
typename Trav::DirHandle searchHandle;
@@ -433,9 +416,7 @@ private:
(shortName[1] == 0 || (shortName[1] == L'.' && shortName[2] == 0)))
continue;
- const Zstring& fullName = endsWith(directory, FILE_NAME_SEPARATOR) ?
- directory + shortName :
- directory + FILE_NAME_SEPARATOR + shortName;
+ const Zstring& fullName = appendSeparator(directory) + shortName;
if (Trav::isSymlink(fileInfo) && !followSymlinks_) //evaluate symlink directly
{
@@ -477,7 +458,7 @@ private:
{
const dst::RawTime rawTime(Trav::getCreateTimeRaw(fileInfo), Trav::getModTimeRaw(fileInfo));
- if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error)
+ if (dst::fatHasUtcEncoded(rawTime)) //throw std::runtime_error
details.lastWriteTimeRaw = toTimeT(dst::fatDecodeUtcTime(rawTime)); //return real UTC time; throw (std::runtime_error)
else
markForDstHack.push_back(std::make_pair(fullName, Trav::getModTimeRaw(fileInfo)));
@@ -504,7 +485,7 @@ private:
dstCallback.requestUiRefresh(i->first);
- const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw (std::runtime_error)
+ const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw std::runtime_error
{
//may need to remove the readonly-attribute (e.g. FAT usb drives)
FileUpdateHandle updateHandle(i->first, [=]
@@ -512,7 +493,7 @@ private:
return ::CreateFile(zen::applyLongPathPrefix(i->first).c_str(),
GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
nullptr);
@@ -599,7 +580,7 @@ private:
tryReportingError([&]
{
if (level == 100) //notify endless recursion
- throw FileError(_("Endless loop when traversing directory:") + L"\n\"" + directory + L"\"");
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + _("Endless loop."));
}, sink);
@@ -608,7 +589,7 @@ private:
{
dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/"
if (!dirObj)
- throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}, sink);
if (!dirObj)
@@ -621,7 +602,7 @@ private:
tryReportingError([&]
{
if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0)
- throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
}, sink);
if (!dirEntry) //no more items or ignore error
return;
@@ -633,16 +614,14 @@ private:
(shortName[1] == 0 || (shortName[1] == '.' && shortName[2] == 0)))
continue;
- const Zstring& fullName = endsWith(directory, FILE_NAME_SEPARATOR) ? //e.g. "/"
- directory + shortName :
- directory + FILE_NAME_SEPARATOR + shortName;
+ const Zstring& fullName = appendSeparator(directory) + shortName;
struct ::stat fileInfo = {};
bool haveData = false;
tryReportingError([&]
{
if (::lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks
- throw FileError(_("Error reading file attributes:") + L"\n\"" + fullName + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(fullName)) + L"\n\n" + getLastErrorFormatted());
haveData = true;
}, sink);
if (!haveData)
diff --git a/zen/file_update_handle.h b/zen/file_update_handle.h
index aa9edebd..716048fd 100644
--- a/zen/file_update_handle.h
+++ b/zen/file_update_handle.h
@@ -24,7 +24,7 @@ public:
const DWORD lastError = ::GetLastError();
if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
{
- zen::ScopeGuard guardErrorCode = zen::makeGuard([&]() { ::SetLastError(lastError); }); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!]
+ //zen::ScopeGuard guardErrorCode = zen::makeGuard([&] { ::SetLastError(lastError); }); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!]
//read-only file attribute may cause trouble: temporarily reset it
const DWORD tmpAttr = ::GetFileAttributes(filenameFmt.c_str());
@@ -32,7 +32,7 @@ public:
{
if (::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL))
{
- guardErrorCode.dismiss();
+ //guardErrorCode.dismiss();
attr = tmpAttr; //"create" guard on read-only attribute
//now try again
diff --git a/zen/guid.h b/zen/guid.h
index 42119674..acc07fa0 100644
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -28,7 +28,8 @@ namespace zen
inline
std::string generateGUID() //creates a 16 byte GUID
{
- boost::uuids::uuid nativeRep = boost::uuids::random_generator()();
+ boost::uuids::uuid nativeRep = boost::uuids::random_generator()(); //generator is thread-safe like an int
+ //perf: generator: 0.22ms per call; retrieve GUID: 0.12µs per call
return std::string(nativeRep.begin(), nativeRep.end());
}
}
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index 83643906..db3207d3 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -12,7 +12,7 @@
namespace zen
{
-//handle filenames longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix (Reference: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath)
+//handle filenames longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix; see: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
/*
1. path must be absolute
2. if path is smaller than MAX_PATH nothing is changed!
diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp
index d8657ea2..35ffc4e1 100644
--- a/zen/notify_removal.cpp
+++ b/zen/notify_removal.cpp
@@ -12,19 +12,6 @@
using namespace zen;
-/*
-//convert bitmask into "real" drive-letter
-Zstring getDriveFromMask(ULONG unitmask)
-{
- for (int i = 0; i < 26; ++i)
- {
- if (unitmask & 0x1)
- return Zstring() + static_cast<DefaultChar>(DefaultChar('A') + i) + DefaultStr(":\\");
- unitmask >>= 1;
- }
- return Zstring();
-}
-*/
namespace
{
@@ -64,7 +51,7 @@ private:
friend LRESULT CALLBACK topWndProc(HWND, UINT, WPARAM, LPARAM);
void processMessage(UINT message, WPARAM wParam, LPARAM lParam);
- const HINSTANCE process;
+ const HINSTANCE hMainModule;
HWND windowHandle;
std::set<Listener*> listener;
@@ -74,39 +61,39 @@ private:
const wchar_t MessageProvider::WINDOW_NAME[] = L"E6AD5EB1-527B-4EEF-AC75-27883B233380"; //random name
-LRESULT CALLBACK topWndProc(HWND hwnd, //handle to window
- UINT uMsg, //message identifier
- WPARAM wParam, //first message parameter
- LPARAM lParam) //second message parameter
+LRESULT CALLBACK topWndProc(HWND hwnd, //handle to window
+ UINT uMsg, //message identifier
+ WPARAM wParam, //first message parameter
+ LPARAM lParam) //second message parameter
{
if (messageProviderConstructed) //attention: this callback is triggered in the middle of singleton construction! It is a bad idea to to call back at this time!
try
{
MessageProvider::instance().processMessage(uMsg, wParam, lParam); //not supposed to throw
}
- catch (...) {}
+ catch (...) { assert(false); }
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
MessageProvider::MessageProvider() :
- process(::GetModuleHandle(nullptr)), //get program's module handle
+ hMainModule(::GetModuleHandle(nullptr)), //get program's module handle
windowHandle(nullptr)
{
- if (!process)
+ if (!hMainModule)
throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (GetModuleHandle)");
//register the main window class
WNDCLASS wc = {};
wc.lpfnWndProc = topWndProc;
- wc.hInstance = process;
+ wc.hInstance = hMainModule;
wc.lpszClassName = WINDOW_NAME;
if (::RegisterClass(&wc) == 0)
throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (RegisterClass)");
- zen::ScopeGuard guardClass = zen::makeGuard([&]() { ::UnregisterClass(WINDOW_NAME, process); });
+ ScopeGuard guardClass = makeGuard([&] { ::UnregisterClass(WINDOW_NAME, hMainModule); });
//create dummy-window
windowHandle = ::CreateWindow(WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word!
@@ -117,9 +104,9 @@ MessageProvider::MessageProvider() :
0, //int nWidth,
0, //int nHeight,
0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)!
- nullptr, //HMENU hMenu,
- process, //HINSTANCE hInstance,
- nullptr); //LPVOID lpParam
+ nullptr, //HMENU hMenu,
+ hMainModule, //HINSTANCE hInstance,
+ nullptr); //LPVOID lpParam
if (!windowHandle)
throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (CreateWindow)");
@@ -132,7 +119,7 @@ MessageProvider::~MessageProvider()
//clean-up in reverse order
::DestroyWindow(windowHandle);
::UnregisterClass(WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word!
- process); //HINSTANCE hInstance
+ hMainModule); //HINSTANCE hInstance
}
@@ -147,10 +134,10 @@ void MessageProvider::processMessage(UINT message, WPARAM wParam, LPARAM lParam)
class NotifyRequestDeviceRemoval::Pimpl : private MessageProvider::Listener
{
public:
- Pimpl(NotifyRequestDeviceRemoval& parent, HANDLE hDir) : //throw (FileError)
+ Pimpl(NotifyRequestDeviceRemoval& parent, HANDLE hDir) : //throw FileError
parent_(parent)
{
- MessageProvider::instance().registerListener(*this); //throw (FileError)
+ MessageProvider::instance().registerListener(*this); //throw FileError
//register handles to receive notifications
DEV_BROADCAST_HANDLE filter = {};
diff --git a/zen/perf.h b/zen/perf.h
index ea8991a8..f7f7e6d0 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -8,116 +8,66 @@
#define DEBUG_PERF_HEADER
#include "deprecate.h"
+#include "tick_count.h"
#ifdef FFS_WIN
#include <sstream>
-#include "win.h" //includes "windows.h"
#else
#include <iostream>
-#include <time.h>
#endif
-//two macros for quick performance measurements
-#define PERF_START CpuTimer perfTest;
+//############# two macros for quick performance measurements ###############
+#define PERF_START zen::PerfTimer perfTest;
#define PERF_STOP perfTest.showResult();
+//###########################################################################
-#ifdef FFS_WIN
-class CpuTimer
+namespace zen
+{
+class PerfTimer
{
public:
class TimerError {};
ZEN_DEPRECATE
- CpuTimer() : frequency(), startTime(), resultShown(false)
+ PerfTimer() : ticksPerSec_(ticksPerSec()), startTime(), resultShown(false)
{
- SetThreadAffinity dummy;
- if (!::QueryPerformanceFrequency(&frequency))
- throw TimerError();
- if (!::QueryPerformanceCounter (&startTime))
+ //std::clock() - "counts CPU time in C and wall time in VC++" - WTF!???
+#ifdef FFS_WIN
+ if (::SetThreadAffinityMask(::GetCurrentThread(), 1) == 0) throw TimerError(); //"should not be required unless there are bugs in BIOS or HAL" - msdn, QueryPerformanceCounter
+#endif
+ startTime = getTicks();
+ if (ticksPerSec_ == 0 || !startTime.isValid())
throw TimerError();
}
- ~CpuTimer()
- {
- if (!resultShown)
- showResult();
- }
+ ~PerfTimer() { if (!resultShown) showResult(); }
void showResult()
{
- SetThreadAffinity dummy;
- LARGE_INTEGER currentTime = {};
- if (!::QueryPerformanceCounter(&currentTime))
+ const TickVal now = getTicks();
+ if (!now.isValid())
throw TimerError();
- const auto delta = static_cast<long>(1000.0 * (currentTime.QuadPart - startTime.QuadPart) / frequency.QuadPart);
+ const auto delta = static_cast<long>(1000.0 * (now - startTime) / ticksPerSec_);
+#ifdef FFS_WIN
std::ostringstream ss;
ss << delta << " ms";
-
::MessageBoxA(nullptr, ss.str().c_str(), "Timer", 0);
- resultShown = true;
-
- if (!::QueryPerformanceCounter(&startTime))
- throw TimerError(); //don't include call to MessageBox()!
- }
-
-private:
- class SetThreadAffinity
- {
- public:
- SetThreadAffinity() : oldmask(::SetThreadAffinityMask(::GetCurrentThread(), 1)) { if (oldmask == 0) throw TimerError(); }
- ~SetThreadAffinity() { ::SetThreadAffinityMask(::GetCurrentThread(), oldmask); }
- private:
- SetThreadAffinity(const SetThreadAffinity&);
- SetThreadAffinity& operator=(const SetThreadAffinity&);
- const DWORD_PTR oldmask;
- };
-
- LARGE_INTEGER frequency;
- LARGE_INTEGER startTime;
- bool resultShown;
-};
-
-
#else
-class CpuTimer
-{
-public:
- class TimerError {};
-
- ZEN_DEPRECATE
- CpuTimer() : startTime(), resultShown(false)
- {
- //clock() seems to give grossly incorrect results: multi core issue?
- //gettimeofday() seems fine but is deprecated
- if (::clock_gettime(CLOCK_MONOTONIC_RAW, &startTime) != 0) //CLOCK_MONOTONIC measures time reliably across processors!
- throw TimerError();
- }
-
- ~CpuTimer()
- {
- if (!resultShown)
- showResult();
- }
-
- void showResult()
- {
- timespec currentTime = {};
- if (::clock_gettime(CLOCK_MONOTONIC_RAW, &currentTime) != 0)
- throw TimerError();
-
- const auto delta = static_cast<long>((currentTime.tv_sec - startTime.tv_sec) * 1000.0 + (currentTime.tv_nsec - startTime.tv_nsec) / 1000000.0);
std::clog << "Perf: duration: " << delta << " ms\n";
+#endif
resultShown = true;
- if (::clock_gettime(CLOCK_MONOTONIC_RAW, &startTime) != 0)
+ startTime = getTicks(); //don't include call to MessageBox()!
+ if (!startTime.isValid())
throw TimerError();
}
private:
- timespec startTime;
+ const std::int64_t ticksPerSec_;
+ TickVal startTime;
bool resultShown;
};
-#endif
+}
#endif //DEBUG_PERF_HEADER
diff --git a/zen/privilege.cpp b/zen/privilege.cpp
index 23a55bd8..69c820f3 100644
--- a/zen/privilege.cpp
+++ b/zen/privilege.cpp
@@ -15,14 +15,14 @@ bool privilegeIsActive(LPCTSTR privilege) //throw FileError
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_QUERY, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
PRIVILEGE_SET priv = {};
priv.PrivilegeCount = 1;
@@ -34,7 +34,7 @@ bool privilegeIsActive(LPCTSTR privilege) //throw FileError
if (!::PrivilegeCheck(hToken, //__in HANDLE ClientToken,
&priv, //__inout PPRIVILEGE_SET RequiredPrivileges,
&alreadyGranted)) //__out LPBOOL pfResult
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
return alreadyGranted == TRUE;
}
@@ -46,14 +46,14 @@ void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_ADJUST_PRIVILEGES, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
TOKEN_PRIVILEGES tp = {};
tp.PrivilegeCount = 1;
@@ -66,10 +66,10 @@ void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
0, //__in DWORD BufferLength,
nullptr, //__out_opt PTOKEN_PRIVILEGES PreviousState,
nullptr)) //__out_opt PDWORD ReturnLength
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success!
- throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\"") + L"\n\n" + getLastErrorFormatted());
}
diff --git a/zen/process_status.h b/zen/process_priority.h
index 15266b28..15266b28 100644
--- a/zen/process_status.h
+++ b/zen/process_priority.h
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
new file mode 100644
index 00000000..e53b5f6a
--- /dev/null
+++ b/zen/recycler.cpp
@@ -0,0 +1,280 @@
+// **************************************************************************
+// * 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 "recycler.h"
+#include <stdexcept>
+#include <iterator>
+#include <zen/file_handling.h>
+
+#ifdef FFS_WIN
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <zen/dll.h>
+#include <zen/win.h> //includes "windows.h"
+#include <zen/assert_static.h>
+#include <zen/win_ver.h>
+#include <zen/long_path_prefix.h>
+#include "IFileOperation/file_op.h"
+
+#elif defined FFS_LINUX
+#include <zen/scope_guard.h>
+#include <sys/stat.h>
+#include <gio/gio.h>
+#endif
+
+using namespace zen;
+
+
+namespace
+{
+#ifdef FFS_WIN
+/*
+Performance test: delete 1000 files
+------------------------------------
+SHFileOperation - single file 33s
+SHFileOperation - multiple files 2,1s
+IFileOperation - single file 33s
+IFileOperation - multiple files 2,1s
+
+=> SHFileOperation and IFileOperation have nearly IDENTICAL performance characteristics!
+
+Nevertheless, let's use IFileOperation for better error reporting!
+*/
+const bool useIFileOperation = vistaOrLater(); //caveat: function scope static initialization is not thread-safe in VS 2010!
+
+//(try to) enhance error messages by showing which processed lock the file
+Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string if none found or error occurred
+{
+ if (vistaOrLater())
+ {
+ using namespace fileop;
+ const DllFun<FunType_getLockingProcesses> getLockingProcesses(getDllName(), funName_getLockingProcesses);
+ const DllFun<FunType_freeString> freeString (getDllName(), funName_freeString);
+
+ if (getLockingProcesses && freeString)
+ {
+ const wchar_t* procList = nullptr;
+ if (getLockingProcesses(filename.c_str(), procList))
+ {
+ ZEN_ON_SCOPE_EXIT(freeString(procList));
+ return procList;
+ }
+ }
+ }
+ return Zstring();
+}
+#endif
+}
+
+
+bool zen::moveToRecycleBin(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!
+
+#ifdef FFS_WIN
+ //::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL);
+ //warning: moving long file paths to recycler does not work!
+ //both ::SHFileOperation() and ::IFileOperation() cannot delete a folder named "System Volume Information" with normal attributes but shamelessly report success
+ //both ::SHFileOperation() and ::IFileOperation() can't handle \\?\-prefix!
+
+ if (useIFileOperation) //new recycle bin usage: available since Vista
+ {
+ using namespace fileop;
+ const DllFun<FunType_moveToRecycleBin> moveToRecycler(getDllName(), funName_moveToRecycleBin);
+ const DllFun<FunType_getLastError> getLastError (getDllName(), funName_getLastError);
+
+ if (!moveToRecycler || !getLastError)
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", fmtFileName(filename)) + L"\n\n" +
+ replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
+
+ std::vector<const wchar_t*> filenames;
+ filenames.push_back(filename.c_str());
+
+ if (!moveToRecycler(&filenames[0], filenames.size()))
+ {
+ const std::wstring shortMsg = replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", fmtFileName(filename));
+
+ //if something is locking our file -> emit better error message!
+ const Zstring procList = getLockingProcessNames(filename); //throw()
+ if (!procList.empty())
+ throw FileError(shortMsg + L"\n\n" + _("The file is locked by another process:") + L"\n" + procList);
+
+ throw FileError(shortMsg + L"\n\n" + getLastError());
+ }
+ }
+ else //regular recycle bin usage: available since XP
+ {
+ const Zstring& filenameDoubleNull = filename + L'\0';
+
+ SHFILEOPSTRUCT fileOp = {};
+ fileOp.hwnd = nullptr;
+ fileOp.wFunc = FO_DELETE;
+ fileOp.pFrom = filenameDoubleNull.c_str();
+ fileOp.pTo = nullptr;
+ fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+ fileOp.fAnyOperationsAborted = false;
+ fileOp.hNameMappings = nullptr;
+ fileOp.lpszProgressTitle = nullptr;
+
+ //"You should use fully-qualified path names with this function. Using it with relative path names is not thread safe."
+ if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
+ {
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", fmtFileName(filename)));
+ }
+ }
+
+#elif defined FFS_LINUX
+ GFile* file = g_file_new_for_path(filename.c_str()); //never fails according to docu
+ ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
+
+ GError* error = nullptr;
+ ZEN_ON_SCOPE_EXIT(if (error) g_error_free(error););
+
+ if (!g_file_trash(file, nullptr, &error))
+ {
+ const std::wstring shortMsg = replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", fmtFileName(filename));
+
+ if (!error)
+ throw FileError(shortMsg + L"\n\n" + L"Unknown error.");
+
+ //implement same behavior as in Windows: if recycler is not existing, delete permanently
+ if (error->code == G_IO_ERROR_NOT_SUPPORTED)
+ {
+ struct stat fileInfo = {};
+ if (::lstat(filename.c_str(), &fileInfo) != 0)
+ return false;
+
+ if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode))
+ removeFile(filename); //throw FileError
+ else if (S_ISDIR(fileInfo.st_mode))
+ removeDirectory(filename); //throw FileError
+ return true;
+ }
+
+ throw FileError(shortMsg + L"\n\n" + L"Glib Error Code " + numberTo<std::wstring>(error->code) + /* L", " +
+ g_quark_to_string(error->domain) + */ L": " + utf8CvrtTo<std::wstring>(error->message));
+ }
+#endif
+ return true;
+}
+
+
+#ifdef FFS_WIN
+zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
+{
+ warn_static("fix XP not working + finish");
+
+ /*
+ const bool canUseFastCheckForRecycler = winXpOrLater();
+ if (!canUseFastCheckForRecycler) //== "checkForRecycleBin"
+ return STATUS_REC_UNKNOWN;
+
+ using namespace fileop;
+ const DllFun<FunType_checkRecycler> checkRecycler(getDllName(), funName_checkRecycler);
+
+ 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);
+ if (hFindRoot == INVALID_HANDLE_VALUE)
+ return STATUS_REC_UNKNOWN;
+ ZEN_ON_SCOPE_EXIT(FindClose(hFindRoot));
+
+ auto shouldSkip = [](const Zstring& shortname) { return shortname == L"." || shortname == L".."; };
+
+ do
+ {
+ 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
+ {
+ WIN32_FIND_DATA dataChild = {};
+ const Zstring childDirPf = rootPathPf + dataRoot.cFileName + L"\\";
+
+ HANDLE hFindChild = ::FindFirstFile(applyLongPathPrefix(childDirPf + L'*').c_str(), &dataChild);
+ if (hFindChild != INVALID_HANDLE_VALUE) //if we can't access a subdir, it's probably not the recycler
+ {
+ ZEN_ON_SCOPE_EXIT(FindClose(hFindChild));
+ do
+ {
+ if (!shouldSkip(dataChild.cFileName) &&
+ (dataChild.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ bool isRecycler = false;
+ if (checkRecycler((childDirPf + dataChild.cFileName).c_str(), isRecycler))
+ {
+ if (isRecycler)
+ return STATUS_REC_EXISTS;
+ }
+ else assert(false);
+ }
+ }
+ while (::FindNextFile(hFindChild, &dataChild)); //ignore errors other than ERROR_NO_MORE_FILES
+ }
+ }
+ }
+ 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
+/*
+We really need access to a similar function to check whether a directory supports trashing and emit a warning if it does not!
+
+The following function looks perfect, alas it is restricted to local files and to the implementation of GIO only:
+
+ gboolean _g_local_file_has_trash_dir(const char* dirname, dev_t dir_dev);
+ See: http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.h
+
+ Just checking for "G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH" is not correct, since we find in
+ http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.c
+
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
+ writable && parent_info->has_trash_dir);
+
+ => We're NOT interested in whether the specified folder can be trashed, but whether it supports thrashing its child elements! (Only support, not actual write access!)
+ This renders G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH useless for this purpose.
+*/
+#endif
diff --git a/lib/recycler.h b/zen/recycler.h
index 8eab5b21..952deec2 100644
--- a/lib/recycler.h
+++ b/zen/recycler.h
@@ -30,7 +30,7 @@ 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); //return "true" if file/dir was actually deleted; throw (FileError)
+bool moveToRecycleBin(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 e9fe149a..78d99832 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -159,6 +159,7 @@ template <class K, class V> class hash_map : public std::unordered_map<K, V> {};
#endif
//as long as variadic templates are not available in MSVC
+template<class T> inline std::unique_ptr<T> make_unique() { return std::unique_ptr<T>(new T); }
template<class T, class Arg1> inline std::unique_ptr<T> make_unique(Arg1&& arg1) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1))); }
template<class T, class Arg1, class Arg2> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))); }
template<class T, class Arg1, class Arg2, class Arg3> inline std::unique_ptr<T> make_unique(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3) { return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Arg3>(arg3))); }
diff --git a/zen/string_base.h b/zen/string_base.h
index 82793a49..45f65ab8 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -21,7 +21,7 @@ namespace zen
/*
Allocator Policy:
-----------------
- void* allocate(size_t size) //throw (std::bad_alloc)
+ void* allocate(size_t size) //throw std::bad_alloc
void deallocate(void* ptr)
size_t calcCapacity(size_t length)
*/
@@ -29,7 +29,7 @@ class AllocatorOptimalSpeed //exponential growth + min size
{
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* 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
};
@@ -38,7 +38,7 @@ public:
class AllocatorOptimalMemory //no wasted memory, but more reallocations required when manipulating string
{
public:
- static void* allocate(size_t size) { return ::operator new(size); } //throw (std::bad_alloc)
+ 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 length; }
};
@@ -194,7 +194,7 @@ public:
Zbase(const Char* source, size_t length);
Zbase(const Zbase& source);
Zbase(Zbase&& tmp);
- explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; return buffer[0]; ups...
+ explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; return buffer[0]; ups... forgot &, but no error
//allow explicit construction from different string type, prevent ambiguity via SFINAE
template <class S> explicit Zbase(const S& other, typename S::value_type = 0);
~Zbase();
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 85eef5df..04ba1eef 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -26,18 +26,19 @@ namespace zen
template <class Char> bool isWhiteSpace(Char ch);
template <class Char> bool isDigit (Char ch); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only!
-template <class S, class T> bool startsWith(const S& str, const T& prefix); //both S and T can be strings or char/wchar_t arrays or simple char/wchar_t
-template <class S, class T> bool endsWith (const S& str, const T& postfix); //
+template <class S, class T> bool startsWith(const S& str, const T& prefix); //
+template <class S, class T> bool endsWith (const S& str, const T& postfix); //both S and T can be strings or char/wchar_t arrays or simple char/wchar_t
+template <class S, class T> bool contains (const S& str, const T& term); //
-template <class S, class T> S afterLast (const S& str, const T& ch); //returns the whole string if ch not found
-template <class S, class T> S beforeLast (const S& str, const T& ch); //returns empty string if ch not found
-template <class S, class T> S afterFirst (const S& str, const T& ch); //returns empty string if ch not found
-template <class S, class T> S beforeFirst(const S& str, const T& ch); //returns the whole string if ch not found
+template <class S, class T> S afterLast (const S& str, const T& term); //returns the whole string if term not found
+template <class S, class T> S beforeLast (const S& str, const T& term); //returns empty string if term not found
+template <class S, class T> S afterFirst (const S& str, const T& term); //returns empty string if term not found
+template <class S, class T> S beforeFirst(const S& str, const T& term); //returns the whole string if term not found
template <class S, class T> std::vector<S> split(const S& str, const T& delimiter);
template <class S> void trim(S& str, bool fromLeft = true, bool fromRight = true);
-template <class S, class T, class U> void replace ( S& str, const T& oldOne, const U& newOne, bool replaceAll = true);
-template <class S, class T, class U> S replaceCpy(const S& str, const T& oldOne, const U& newOne, bool replaceAll = true);
+template <class S, class T, class U> void replace ( S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
+template <class S, class T, class U> S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
//high-performance conversion between numbers and strings
template <class S, class T, class Num> S printNumber(const T& format, const Num& number); //format a single number using std::snprintf()
@@ -133,42 +134,62 @@ bool endsWith(const S& str, const T& postfix)
}
-//returns the whole string if ch not found
template <class S, class T> inline
-S afterLast(const S& str, const T& ch)
+bool contains(const S& str, const T& term)
+{
+ assert_static(IsStringLike<S>::value && IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
+
+ const size_t strLen = strLength(str);
+ const size_t termLen = strLength(term);
+ if (strLen < termLen)
+ return false;
+
+ const CharType* const strFirst = strBegin(str);
+ const CharType* const strLast = strFirst + strLen;
+ const CharType* const termFirst = strBegin(term);
+
+ return std::search(strFirst, strLast,
+ termFirst, termFirst + termLen) != strLast;
+}
+
+
+//returns the whole string if term not found
+template <class S, class T> inline
+S afterLast(const S& str, const T& term)
{
assert_static(IsStringLike<T>::value);
typedef typename GetCharType<S>::Type CharType;
- const size_t chLen = strLength(ch);
+ const size_t termLen = strLength(term);
- const CharType* const strFirst = strBegin(str);
- const CharType* const strLast = strFirst + strLength(str);
- const CharType* const chFirst = strBegin(ch);
+ const CharType* const strFirst = strBegin(str);
+ const CharType* const strLast = strFirst + strLength(str);
+ const CharType* const termFirst = strBegin(term);
const CharType* iter = search_last(strFirst, strLast,
- chFirst, chFirst + chLen);
+ termFirst, termFirst + termLen);
if (iter == strLast)
return str;
- iter += chLen;
+ iter += termLen;
return S(iter, strLast - iter);
}
-//returns empty string if ch not found
+//returns empty string if term not found
template <class S, class T> inline
-S beforeLast(const S& str, const T& ch)
+S beforeLast(const S& str, const T& term)
{
assert_static(IsStringLike<T>::value);
typedef typename GetCharType<S>::Type CharType;
- const CharType* const strFirst = strBegin(str);
- const CharType* const strLast = strFirst + strLength(str);
- const CharType* const chFirst = strBegin(ch);
+ const CharType* const strFirst = strBegin(str);
+ const CharType* const strLast = strFirst + strLength(str);
+ const CharType* const termFirst = strBegin(term);
const CharType* iter = search_last(strFirst, strLast,
- chFirst, chFirst + strLength(ch));
+ termFirst, termFirst + strLength(term));
if (iter == strLast)
return S();
@@ -176,40 +197,40 @@ S beforeLast(const S& str, const T& ch)
}
-//returns empty string if ch not found
+//returns empty string if term not found
template <class S, class T> inline
-S afterFirst(const S& str, const T& ch)
+S afterFirst(const S& str, const T& term)
{
assert_static(IsStringLike<T>::value);
typedef typename GetCharType<S>::Type CharType;
- const size_t chLen = strLength(ch);
- const CharType* const strFirst = strBegin(str);
- const CharType* const strLast = strFirst + strLength(str);
- const CharType* const chFirst = strBegin(ch);
+ const size_t termLen = strLength(term);
+ const CharType* const strFirst = strBegin(str);
+ const CharType* const strLast = strFirst + strLength(str);
+ const CharType* const termFirst = strBegin(term);
const CharType* iter = std::search(strFirst, strLast,
- chFirst, chFirst + chLen);
+ termFirst, termFirst + termLen);
if (iter == strLast)
return S();
- iter += chLen;
+ iter += termLen;
return S(iter, strLast - iter);
}
-//returns the whole string if ch not found
+//returns the whole string if term not found
template <class S, class T> inline
-S beforeFirst(const S& str, const T& ch)
+S beforeFirst(const S& str, const T& term)
{
assert_static(IsStringLike<T>::value);
typedef typename GetCharType<S>::Type CharType;
- const CharType* const strFirst = strBegin(str);
- const CharType* const chFirst = strBegin(ch);
+ const CharType* const strFirst = strBegin(str);
+ const CharType* const termFirst = strBegin(term);
return S(strFirst, std::search(strFirst, strFirst + strLength(str),
- chFirst, chFirst + strLength(ch)) - strFirst);
+ termFirst, termFirst + strLength(term)) - strFirst);
}
@@ -262,22 +283,22 @@ typename EnableIf<!HasMember_append<S>::value>::Type stringAppend(S& str, const
template <class S, class T, class U> inline
-S replaceCpy(const S& str, const T& oldOne, const U& newOne, bool replaceAll)
+S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
{
assert_static(IsStringLike<T>::value && IsStringLike<U>::value);
typedef typename GetCharType<S>::Type CharType;
- const size_t oldLen = strLength(oldOne);
- const size_t newLen = strLength(newOne);
+ const size_t oldLen = strLength(oldTerm);
+ const size_t newLen = strLength(newTerm);
S output;
const CharType* strPos = strBegin(str);
const CharType* const strEnd = strPos + strLength(str);
- const CharType* const oldBegin = strBegin(oldOne);
- const CharType* const newBegin = strBegin(newOne);
+ const CharType* const oldBegin = strBegin(oldTerm);
+ const CharType* const newBegin = strBegin(newTerm);
for (;;)
{
@@ -301,9 +322,9 @@ S replaceCpy(const S& str, const T& oldOne, const U& newOne, bool replaceAll)
template <class S, class T, class U> inline
-void replace(S& str, const T& oldOne, const U& newOne, bool replaceAll)
+void replace(S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
{
- str = replaceCpy(str, oldOne, newOne, replaceAll);
+ str = replaceCpy(str, oldTerm, newTerm, replaceAll);
}
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 006e4ea0..06239b5a 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -78,7 +78,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
nullptr);
if (hLink == INVALID_HANDLE_VALUE)
- throw FileError(_("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)) + L"\n\n" + getLastErrorFormatted());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hLink));
//respect alignment issues...
@@ -94,7 +94,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
bufferSize, //__in DWORD nOutBufferSize,
&bytesReturned, //__out_opt LPDWORD lpBytesReturned,
nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- throw FileError(_("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)) + L"\n\n" + getLastErrorFormatted());
REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(&buffer[0]); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
@@ -110,7 +110,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
}
else
- throw FileError(_("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"" + L"\n\n" + L"Not a symbolic link or junction!");
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)) + L"\n\n" + L"Not a symbolic link or junction!");
//absolute symlinks and junctions technically start with \??\ while relative ones do not
if (startsWith(output, Zstr("\\??\\")))
@@ -125,7 +125,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
const int bytesWritten = ::readlink(linkPath.c_str(), &buffer[0], BUFFER_SIZE);
if (bytesWritten < 0 || bytesWritten >= BUFFER_SIZE)
{
- std::wstring errorMessage = _("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"";
+ std::wstring errorMessage = replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath));
if (bytesWritten < 0)
errorMessage += L"\n\n" + getLastErrorFormatted();
throw FileError(errorMessage);
diff --git a/zen/thread.h b/zen/thread.h
index 4598ea99..ba9a46e2 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -8,6 +8,8 @@
#define BOOST_THREAD_WRAP_H
//temporary solution until C++11 thread becomes fully available
+#include <vector>
+#include <memory>
#ifdef __MINGW32__
#pragma GCC diagnostic push
@@ -39,12 +41,31 @@ Example:
template <class Function>
auto async(Function fun) -> boost::unique_future<decltype(fun())>;
+//wait for all with a time limit: return true if *all* results are available!
template<class InputIterator, class Duration>
-void wait_for_all_timed(InputIterator first, InputIterator last, const Duration& wait_duration);
+bool wait_for_all_timed(InputIterator first, InputIterator last, const Duration& wait_duration);
+//wait until first job is successful or all failed
+template <class T>
+class RunUntilFirstHit
+{
+public:
+ RunUntilFirstHit();
+
+ template <class Fun>
+ void addJob(Fun f); //f must return a std::unique_ptr<T> containing a value if successful
+ template <class Duration>
+ bool timedWait(const Duration& duration) const; //true: "get()" is ready, false: time elapsed
+ //return first value or none if all jobs failed; blocks until result is ready!
+ std::unique_ptr<T> get() const; //must be called only once!
+private:
+ class AsyncResult;
+ std::vector<boost::thread> workload;
+ std::shared_ptr<AsyncResult> result;
+};
@@ -72,21 +93,107 @@ auto async2(Function fun) -> boost::unique_future<T> //workaround VS2010 bug: bo
}
-template <class Function> inline auto async(Function fun) -> boost::unique_future<decltype(fun())> { return async2<decltype(fun())>(fun); }
+template <class Function> inline
+auto async(Function fun) -> boost::unique_future<decltype(fun())> { return async2<decltype(fun())>(fun); }
template<class InputIterator, class Duration> inline
-void wait_for_all_timed(InputIterator first, InputIterator last, const Duration& wait_duration)
+bool wait_for_all_timed(InputIterator first, InputIterator last, const Duration& wait_duration)
{
const boost::system_time endTime = boost::get_system_time() + wait_duration;
while (first != last)
{
- first->timed_wait_until(endTime);
- if (boost::get_system_time() >= endTime)
- return;
+ if (!first->timed_wait_until(endTime))
+ return false; //time elapsed
++first;
}
+ return true;
}
+
+
+template <class T>
+class RunUntilFirstHit<T>::AsyncResult
+{
+public:
+ AsyncResult() :
+#ifndef NDEBUG
+ returnedResult(false),
+#endif
+ jobsFinished(0) {}
+
+ //context: worker threads
+ void reportFinished(std::unique_ptr<T>&& result)
+ {
+ {
+ boost::unique_lock<boost::mutex> dummy(lockResult);
+ ++jobsFinished;
+ if (!result_)
+ result_ = std::move(result);
+ }
+ conditionJobDone.notify_one();
+ //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
+ }
+
+ //context: main thread
+ template <class Duration>
+ bool waitForResult(size_t jobsTotal, const Duration& duration)
+ {
+ boost::unique_lock<boost::mutex> dummy(lockResult);
+ return conditionJobDone.timed_wait(dummy, duration, [&] { return this->jobDone(jobsTotal); });
+ //use timed_wait predicate if exitting before condition is reached: http://www.boost.org/doc/libs/1_49_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref.condition_variable.timed_wait_rel
+ }
+
+ std::unique_ptr<T> getResult(size_t jobsTotal)
+ {
+ boost::unique_lock<boost::mutex> dummy(lockResult);
+
+ while (!jobDone(jobsTotal))
+ conditionJobDone.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point!
+
+#ifndef NDEBUG
+ assert(!returnedResult);
+ returnedResult = true;
+#endif
+ return std::move(result_);
+ }
+
+private:
+ bool jobDone(size_t jobsTotal) const { return result_ || (jobsFinished >= jobsTotal); } //call while locked!
+#ifndef NDEBUG
+ bool returnedResult;
+#endif
+
+ boost::mutex lockResult;
+ size_t jobsFinished; //
+ std::unique_ptr<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
+ boost::condition_variable conditionJobDone;
+};
+
+
+
+template <class T> inline
+RunUntilFirstHit<T>::RunUntilFirstHit() : result(std::make_shared<AsyncResult>()) {}
+
+
+template <class T>
+template <class Fun> inline
+void RunUntilFirstHit<T>::addJob(Fun f) //f must return a std::unique_ptr<T> containing a value on success
+{
+ auto result2 = result; //VC11: this is ridiculous!!!
+ workload.push_back(boost::thread([result2, f]
+ {
+ result2->reportFinished(f());
+ }));
+}
+
+
+template <class T>
+template <class Duration> inline
+bool RunUntilFirstHit<T>::timedWait(const Duration& duration) const { return result->waitForResult(workload.size(), duration); }
+
+
+template <class T> inline
+std::unique_ptr<T> RunUntilFirstHit<T>::get() const { return result->getResult(workload.size()); }
}
#endif //BOOST_THREAD_WRAP_H
diff --git a/zen/tick_count.h b/zen/tick_count.h
new file mode 100644
index 00000000..37c7cc59
--- /dev/null
+++ b/zen/tick_count.h
@@ -0,0 +1,114 @@
+// **************************************************************************
+// * This file is part of the zenXML project. It is distributed under the *
+// * Boost Software License, Version 1.0. See accompanying file *
+// * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt. *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef ZEN_TICK_COUNT_HEADER_3807326
+#define ZEN_TICK_COUNT_HEADER_3807326
+
+#include <cstdint>
+#include "type_traits.h"
+#include "assert_static.h"
+
+#ifdef FFS_WIN
+#include "win.h" //includes "windows.h"
+#elif defined FFS_LINUX
+#include <time.h> //Posix ::clock_gettime()
+#endif
+
+namespace zen
+{
+//a portable "GetTickCount()" using "wall time equivalent" - e.g. no jumps due to ntp time corrections
+class TickVal;
+std::int64_t operator-(const TickVal& lhs, const TickVal& rhs);
+
+std::int64_t ticksPerSec(); //return 0 on error
+TickVal getTicks(); //return invalid value on error
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//############################ implementation ##############################
+class TickVal
+{
+public:
+#ifdef FFS_WIN
+ typedef LARGE_INTEGER NativeVal;
+#elif defined FFS_LINUX
+ typedef timespec NativeVal;
+#endif
+
+ TickVal() : val_() {}
+ TickVal(const NativeVal& val) : val_(val) {}
+
+ inline friend
+ std::int64_t operator-(const TickVal& lhs, const TickVal& rhs)
+ {
+#ifdef FFS_WIN
+ assert_static(IsSignedInt<decltype(lhs.val_.QuadPart)>::value);
+ return lhs.val_.QuadPart - rhs.val_.QuadPart;
+#elif defined FFS_LINUX
+ assert_static(IsSignedInt<decltype(lhs.val_.tv_sec)>::value);
+ assert_static(IsSignedInt<decltype(lhs.val_.tv_nsec)>::value);
+ return static_cast<std::int64_t>(lhs.val_.tv_sec - rhs.val_.tv_sec) * 1000000000.0 + lhs.val_.tv_nsec - rhs.val_.tv_nsec;
+#endif
+ }
+
+ bool isValid() const { return *this - TickVal() != 0; }
+
+private:
+ NativeVal val_;
+};
+
+
+inline
+std::int64_t ticksPerSec() //return 0 on error
+{
+#ifdef FFS_WIN
+ LARGE_INTEGER frequency = {};
+ if (!::QueryPerformanceFrequency(&frequency))
+ return 0;
+ return frequency.QuadPart;
+
+#elif defined FFS_LINUX
+ return 1000000000; //precision: nanoseconds
+#endif
+}
+
+
+inline
+TickVal getTicks() //return 0 on error
+{
+#ifdef FFS_WIN
+ LARGE_INTEGER now = {};
+ if (!::QueryPerformanceCounter(&now)) //msdn: SetThreadAffinityMask() may be required if there are bugs in BIOS or HAL"
+ return TickVal();
+
+#elif defined FFS_LINUX
+ //gettimeofday() seems fine but is deprecated
+ timespec now = {};
+ if (::clock_gettime(CLOCK_MONOTONIC_RAW, &now) != 0) //CLOCK_MONOTONIC measures time reliably across processors!
+ return TickVal();
+#endif
+ return now;
+}
+}
+
+#endif //ZEN_TICK_COUNT_HEADER_3807326
diff --git a/zen/time.h b/zen/time.h
index b26fb0ad..729b30bc 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -11,6 +11,7 @@
#include <ctime>
#include "string_tools.h"
+
namespace zen
{
struct TimeComp //replaces "struct std::tm" and SYSTEMTIME
@@ -26,7 +27,7 @@ struct TimeComp //replaces "struct std::tm" and SYSTEMTIME
};
TimeComp localTime (time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components
-time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error
+time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error
//----------------------------------------------------------------------------------------------------------------------------------
@@ -53,6 +54,9 @@ const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M
template <class String>
bool parseTime(const String& format, const String& str, TimeComp& comp); //similar to ::strptime(), return true on success
+//----------------------------------------------------------------------------------------------------------------------------------
+
+
diff --git a/zen/win_ver.h b/zen/win_ver.h
index 464b7264..c2162c61 100644
--- a/zen/win_ver.h
+++ b/zen/win_ver.h
@@ -27,35 +27,29 @@ bool win7OrLater();
+//######################### implementation #########################
+//version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
+//2000 is version 5.0
+//XP is version 5.1
+//Server 2003 is version 5.2
+//Vista is version 6.0
+//Seven is version 6.1
-
-
-
-
-//######################### implementation #########################
namespace impl
{
inline
-bool winXyOrLater(DWORD major, DWORD minor) //migrate: hold version data as static variable, as soon as C++11 thread safe statics are available in VS
+bool winXyOrLater(DWORD major, DWORD minor)
{
OSVERSIONINFO osvi = {};
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (::GetVersionEx(&osvi))
+ if (::GetVersionEx(&osvi)) //38 ns per call! (yes, that's nano!) -> we do NOT miss C++11 thread safe statics right now...
return osvi.dwMajorVersion > major ||
(osvi.dwMajorVersion == major && osvi.dwMinorVersion >= minor);
return false;
}
}
-//version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
-
-//2000 is version 5.0
-//XP is version 5.1
-//Server 2003 is version 5.2
-//Vista is version 6.0
-//Seven is version 6.1
-
inline
bool winXpOrLater() { return impl::winXyOrLater(5, 1); }
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 622fb975..182bad91 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -67,7 +67,7 @@ std::string LeakChecker::rawMemToString(const void* ptr, size_t size)
}
-void LeakChecker::reportProblem(const std::string& message) //throw (std::logic_error)
+void LeakChecker::reportProblem(const std::string& message) //throw std::logic_error
{
#ifdef FFS_WIN
::MessageBoxA(nullptr, message.c_str(), "Error", 0);
diff --git a/zen/zstring.h b/zen/zstring.h
index cb6974e5..8f7486b0 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -47,7 +47,7 @@ private:
~LeakChecker();
static std::string rawMemToString(const void* ptr, size_t size);
- void reportProblem(const std::string& message); //throw (std::logic_error)
+ void reportProblem(const std::string& message); //throw std::logic_error
boost::mutex lockActStrings;
zen::hash_map<const void*, size_t> activeStrings;
@@ -58,7 +58,7 @@ private:
class AllocatorFreeStoreChecked
{
public:
- static void* allocate(size_t size) //throw (std::bad_alloc)
+ static void* allocate(size_t size) //throw std::bad_alloc
{
#ifndef NDEBUG
void* newMem = ::operator new(size);
@@ -115,18 +115,19 @@ typedef char Zchar;
const Zchar FILE_NAME_SEPARATOR = '/';
#else
-#error define platform you are in: FFS_WIN or FFS_LINUX
+#error define your platform: FFS_WIN or FFS_LINUX
#endif
//"The reason for all the fuss above" - Loki/SmartPtr
-//a high-performant string for use as file name in multithreaded contexts
+//a high-performance string for use as file name in multithreaded contexts
typedef zen::Zbase<Zchar, zen::StorageRefCountThreadSafe, AllocatorFreeStoreChecked> Zstring;
-
-
-
-
+inline
+Zstring appendSeparator(Zstring path) //support rvalue references!
+{
+ return endsWith(path, FILE_NAME_SEPARATOR) ? path : (path += FILE_NAME_SEPARATOR);
+}
bgstack15