summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Application.cpp2
-rw-r--r--BUILD/Changelog.txt18
-rw-r--r--BUILD/FreeFileSync.chmbin437982 -> 440642 bytes
-rw-r--r--BUILD/Help/html/Comparison Settings.html34
-rw-r--r--BUILD/Help/html/Daylight Saving Time.html12
-rw-r--r--BUILD/Help/html/Exclude Items.html8
-rw-r--r--BUILD/Help/html/External Applications.html30
-rw-r--r--BUILD/Help/html/RealtimeSync.html2
-rw-r--r--BUILD/Help/html/Run as Service.html12
-rw-r--r--BUILD/Help/html/Schedule a Batch Job.html2
-rw-r--r--BUILD/Help/img/ScheduleBatch.gifbin21107 -> 0 bytes
-rw-r--r--BUILD/Help/img/ScheduleBatch.pngbin0 -> 23029 bytes
-rw-r--r--BUILD/Help/img/create_shortcut.pngbin15610 -> 16086 bytes
-rw-r--r--BUILD/Help/img/schedule_realtimesync.pngbin28856 -> 29072 bytes
-rw-r--r--BUILD/Help/img/shortcut_properties.pngbin29975 -> 29921 bytes
-rw-r--r--BUILD/Help/img/win7scheduler.pngbin28693 -> 28955 bytes
-rw-r--r--BUILD/Languages/arabic.lng1421
-rw-r--r--BUILD/Languages/chinese_simple.lng64
-rw-r--r--BUILD/Languages/chinese_traditional.lng4
-rw-r--r--BUILD/Languages/croatian.lng4
-rw-r--r--BUILD/Languages/czech.lng4
-rw-r--r--BUILD/Languages/danish.lng638
-rw-r--r--BUILD/Languages/dutch.lng67
-rw-r--r--BUILD/Languages/english_uk.lng90
-rw-r--r--BUILD/Languages/finnish.lng4
-rw-r--r--BUILD/Languages/french.lng4
-rw-r--r--BUILD/Languages/german.lng90
-rw-r--r--BUILD/Languages/greek.lng154
-rw-r--r--BUILD/Languages/hebrew.lng4
-rw-r--r--BUILD/Languages/hungarian.lng119
-rw-r--r--BUILD/Languages/italian.lng4
-rw-r--r--BUILD/Languages/japanese.lng4
-rw-r--r--BUILD/Languages/korean.lng4
-rw-r--r--BUILD/Languages/lithuanian.lng4
-rw-r--r--BUILD/Languages/norwegian.lng182
-rw-r--r--BUILD/Languages/polish.lng4
-rw-r--r--BUILD/Languages/portuguese.lng4
-rw-r--r--BUILD/Languages/portuguese_br.lng4
-rw-r--r--BUILD/Languages/romanian.lng4
-rw-r--r--BUILD/Languages/russian.lng4
-rw-r--r--BUILD/Languages/scottish_gaelic.lng4
-rw-r--r--BUILD/Languages/slovenian.lng4
-rw-r--r--BUILD/Languages/spanish.lng4
-rw-r--r--BUILD/Languages/swedish.lng4
-rw-r--r--BUILD/Languages/turkish.lng4
-rw-r--r--BUILD/Languages/ukrainian.lng89
-rw-r--r--BUILD/Resources.zipbin226776 -> 225731 bytes
-rw-r--r--FreeFileSync.cbp538
-rw-r--r--FreeFileSync.vcxproj1
-rw-r--r--RealtimeSync/RealtimeSync.cbp158
-rw-r--r--RealtimeSync/resources.cpp4
-rw-r--r--RealtimeSync/tray_menu.cpp2
-rw-r--r--RealtimeSync/watcher.cpp13
-rw-r--r--algorithm.cpp249
-rw-r--r--algorithm.h10
-rw-r--r--comparison.cpp45
-rw-r--r--file_hierarchy.h6
-rw-r--r--lib/binary.cpp18
-rw-r--r--lib/binary.h2
-rw-r--r--lib/dir_exist_async.h2
-rw-r--r--lib/localization.cpp124
-rw-r--r--lib/lock_holder.h2
-rw-r--r--lib/parse_lng.h191
-rw-r--r--lib/parse_plural.h524
-rw-r--r--lib/perf_check.cpp23
-rw-r--r--lib/perf_check.h1
-rw-r--r--lib/process_xml.cpp95
-rw-r--r--lib/process_xml.h17
-rw-r--r--lib/resources.cpp4
-rw-r--r--lib/status_handler.cpp2
-rw-r--r--lib/status_handler.h2
-rw-r--r--lib/versioning.cpp82
-rw-r--r--lib/versioning.h32
-rw-r--r--process_callback.h22
-rw-r--r--synchronization.cpp716
-rw-r--r--synchronization.h2
-rw-r--r--ui/batch_status_handler.cpp16
-rw-r--r--ui/check_version.cpp7
-rw-r--r--ui/custom_grid.cpp2
-rw-r--r--ui/grid_view.cpp2
-rw-r--r--ui/gui_generated.cpp255
-rw-r--r--ui/gui_generated.h65
-rw-r--r--ui/gui_status_handler.cpp6
-rw-r--r--ui/main_dlg.cpp1088
-rw-r--r--ui/main_dlg.h43
-rw-r--r--ui/progress_indicator.cpp95
-rw-r--r--ui/progress_indicator.h4
-rw-r--r--ui/sync_cfg.cpp4
-rw-r--r--ui/tree_view.cpp8
-rw-r--r--ui/triple_splitter.cpp8
-rw-r--r--version/version.h2
-rw-r--r--version/version.rc4
-rw-r--r--wx+/graph.cpp158
-rw-r--r--wx+/graph.h20
-rw-r--r--wx+/grid.cpp10
-rw-r--r--wx+/pch.h9
-rw-r--r--wx+/shell_execute.h12
-rw-r--r--zen/IFileOperation/file_op.cpp20
-rw-r--r--zen/basic_math.h2
-rw-r--r--zen/debug_memory_leaks.cpp4
-rw-r--r--zen/file_handling.cpp120
-rw-r--r--zen/file_handling.h11
-rw-r--r--zen/file_traverser.h6
-rw-r--r--zen/format_unit.cpp4
-rw-r--r--zen/guid.h3
-rw-r--r--zen/perf.h6
-rw-r--r--zen/process_priority.h6
-rw-r--r--zen/recycler.h3
-rw-r--r--zen/string_base.h19
-rw-r--r--zen/thread.h14
110 files changed, 4406 insertions, 3631 deletions
diff --git a/Application.cpp b/Application.cpp
index 85606613..733311b7 100644
--- a/Application.cpp
+++ b/Application.cpp
@@ -164,7 +164,7 @@ void Application::OnStartApplication(wxIdleEvent&)
#ifdef FFS_WIN
wxToolTip::SetMaxWidth(-1); //disable tooltip wrapping -> Windows only (as of 2.9.2)
#endif
- wxToolTip::SetAutoPop(7000); //tooltip visibilty in ms, 5s seems to be default for Windows
+ wxToolTip::SetAutoPop(7000); //tooltip visibilty in ms, 5s is default for Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/aa511495.aspx
#endif
try
diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt
index 7c82a459..fa82072f 100644
--- a/BUILD/Changelog.txt
+++ b/BUILD/Changelog.txt
@@ -2,6 +2,22 @@
|FreeFileSync|
--------------
+Changelog v5.12
+---------------
+Dynamic statistics adjustment during synchronization
+Allow to save active view filter settings as default (context menu)
+Stay responsive while checking recycle bin existence on slow disks
+Reset option "Delete on both sides" upon each manual deletion
+Added context menu to allow deletion of last used configurations
+Support numpad add/subtract keys for overview tree
+Revised external application integration
+Call external applications for multiple selected items
+Automatically schedule abandoned recycle bin temp directories (.ffs_tmp) for deletion
+Binary comparison speed estimate considers errors and short-circuit evaluation
+Use full time window of sync phase when calculating overall speed
+Added Arabic language
+
+
Changelog v5.11
---------------
New file versioning scheme: move to folder replacing existing files
@@ -208,7 +224,7 @@ Support Ctrl + A in filter dialog
Support large filter lists > 32 kByte
Allow to hide file icons
Avoid switching monitor when main dialog is maximized on multiple monitor systems
-Improved huge XML files loading times by a factor of 3000, saving by a factor of 3
+Improved huge XML file loading times by a factor of 3000, saving by a factor of 3
Restore grid scroll position after repeated comparisons
Show log after sync when non-fatal errors occurred
Fixed crash in UTF8 conversion when processing a corrupted ffs_db file
diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm
index e511c8e0..deb1bb4f 100644
--- a/BUILD/FreeFileSync.chm
+++ b/BUILD/FreeFileSync.chm
Binary files differ
diff --git a/BUILD/Help/html/Comparison Settings.html b/BUILD/Help/html/Comparison Settings.html
index e30b33f5..783b0728 100644
--- a/BUILD/Help/html/Comparison Settings.html
+++ b/BUILD/Help/html/Comparison Settings.html
@@ -3,9 +3,9 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE></TITLE>
- <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.4.1 (Win32)">
<META NAME="CREATED" CONTENT="20091206;16574000">
- <META NAME="CHANGED" CONTENT="20120702;13434800">
+ <META NAME="CHANGED" CONTENT="20130120;18372197">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -27,7 +27,7 @@
<BODY LANG="en-US" DIR="LTR">
<H2 CLASS="western"><FONT FACE="Tahoma, sans-serif"><FONT SIZE=4 STYLE="font-size: 15pt">Comparison
Settings</FONT></FONT></H2>
-<P STYLE="margin-bottom: 0cm"><IMG SRC="../img/CmpSettings.png" NAME="Grafik1" ALIGN=BOTTOM BORDER=0></P>
+<P STYLE="margin-bottom: 0cm"><IMG SRC="../img/CmpSettings.png" NAME="Grafik1" ALIGN=BOTTOM WIDTH=219 HEIGHT=267 BORDER=0></P>
<H3 CLASS="western" STYLE="page-break-after: avoid"><FONT FACE="Tahoma, sans-serif">I.
Compare by &quot;File time and size&quot;</FONT></H3>
<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">This
@@ -65,21 +65,6 @@ distinguished:</FONT></P>
</UL>
</OL>
</OL>
-<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">This
-results into the following categories:</FONT></P>
-<UL>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">left
- only</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">right
- only</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">left
- newer</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">right
- newer</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">equal</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">conflict
- (same date, different size)</FONT></P>
-</UL>
<P STYLE="margin-bottom: 0cm"><BR>
</P>
<H3 CLASS="western" STYLE="page-break-after: avoid"><FONT FACE="Tahoma, sans-serif">II.
@@ -110,17 +95,6 @@ modification time is not taken into account at all.</FONT></P>
</UL>
</OL>
</OL>
-<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">As a
-result the files are separated into the following categories:</FONT></P>
-<UL>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">left
- only</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">right
- only</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">equal</FONT></P>
- <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">different
- content</FONT></P>
-</UL>
<P STYLE="margin-bottom: 0cm"><BR>
</P>
<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Symbolic link
@@ -151,7 +125,7 @@ called symlinks or soft links):</FONT></P>
<P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Note</B></FONT></P>
<LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Under
Windows the symbolic link options apply to all symbolic links,
- <I>&quot;volume mount points&quot; </I>and <I>&quot;NTFS junction
+ <I>&quot;volume mount points&quot; </I>and <I>&quot;NTFS junction
points&quot;</I>.</FONT></P>
<LI><P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm; font-style: normal">
<FONT FACE="Tahoma, sans-serif">Copying symbolic links requires
diff --git a/BUILD/Help/html/Daylight Saving Time.html b/BUILD/Help/html/Daylight Saving Time.html
index d088d807..31c5f8e2 100644
--- a/BUILD/Help/html/Daylight Saving Time.html
+++ b/BUILD/Help/html/Daylight Saving Time.html
@@ -3,9 +3,9 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE></TITLE>
- <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.4.1 (Win32)">
<META NAME="CREATED" CONTENT="20091208;20054200">
- <META NAME="CHANGED" CONTENT="20120511;23112900">
+ <META NAME="CHANGED" CONTENT="20130116;18385122">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -29,10 +29,10 @@ saving time </SPAN><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: no
common problem synchronization software has to deal with are +-1 hour
file time shifts after a Daylight Saving Time (DST) switch has
occurred. This can be observed for example when a FAT-formatted
-volume is compared against an NTFS volume as frequently happening
-with USB memory sticks. Files that previously appeared to be in sync
-are now shown with an one hour modification time offset, although
-they have not been modified by the user or by other means.</FONT></P>
+volume is compared against an NTFS volume as frequently happens with
+USB memory sticks. Files that previously appeared to be in sync are
+now shown with a one hour modification time offset, although they
+have not been modified by the user or by other means.</FONT></P>
<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">The
reason for this strange behavior lies in the way NTFS and FAT drives
store file times: NTFS stores time in UTC format, while FAT uses
diff --git a/BUILD/Help/html/Exclude Items.html b/BUILD/Help/html/Exclude Items.html
index 239b639a..8d4c5979 100644
--- a/BUILD/Help/html/Exclude Items.html
+++ b/BUILD/Help/html/Exclude Items.html
@@ -3,9 +3,9 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE></TITLE>
- <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.4.1 (Win32)">
<META NAME="CREATED" CONTENT="20091206;16574000">
- <META NAME="CHANGED" CONTENT="20120511;23112100">
+ <META NAME="CHANGED" CONTENT="20130109;13371476">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -44,7 +44,7 @@ Exclude items for m<SPAN STYLE="font-weight: normal">irror-sync from
<SPAN STYLE="font-weight: normal">to </SPAN><FONT FACE="Courier New, monospace"><SPAN STYLE="font-weight: normal">D:\Target</SPAN></FONT></FONT></P>
<P STYLE="margin-left: 1.32cm; margin-bottom: 0cm"><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6">
<P STYLE="margin-left: 0.82cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Single
- file </SPAN></FONT><FONT FACE="Courier New, monospace">C:\Source\file.txt:<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Exclude:
+ file </SPAN></FONT><FONT FACE="Courier New, monospace">C:\Source\file.txt:<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Exclude:
</SPAN></FONT><FONT FACE="Courier New, monospace">\file.txt</FONT></P>
<P STYLE="margin-left: 0.82cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Single
folder </SPAN></FONT><FONT FACE="Courier New, monospace">C:\Source\subfolder:<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Exclude:
@@ -64,7 +64,7 @@ Exclude items for m<SPAN STYLE="font-weight: normal">irror-sync from
in their path:<BR></SPAN></FONT>&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Exclude:
</SPAN></FONT><FONT FACE="Courier New, monospace">*temp*</FONT></P>
<P ALIGN=LEFT STYLE="margin-left: 0.82cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-weight: normal">Multiple
- entries separated by semicolon:<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN STYLE="font-weight: normal">Exclude:
+ entries separated by semicolon:<BR></SPAN><FONT FACE="Times New Roman, serif"><SPAN STYLE="font-weight: normal">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN></FONT><SPAN STYLE="font-weight: normal">Exclude:
</SPAN><FONT FACE="Courier New, monospace"><SPAN STYLE="font-weight: normal">*.tmp;
*.doc; *.bak</SPAN></FONT></FONT></P>
</SPAN><BR CLEAR=LEFT><BR>
diff --git a/BUILD/Help/html/External Applications.html b/BUILD/Help/html/External Applications.html
index f9d939dc..bdf08cb5 100644
--- a/BUILD/Help/html/External Applications.html
+++ b/BUILD/Help/html/External Applications.html
@@ -3,9 +3,9 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE></TITLE>
- <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.4.1 (Win32)">
<META NAME="CREATED" CONTENT="20091206;16574000">
- <META NAME="CHANGED" CONTENT="20120904;11283300">
+ <META NAME="CHANGED" CONTENT="20130122;19292537">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -26,28 +26,28 @@ applications</FONT></FONT></H2>
<P STYLE="margin-bottom: 0cm"><BR>
</P>
<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">By
-default FreeFileSync opens the operating system's standard file
-browser on each mouse double-click by invoking &quot;<FONT FACE="Courier New, monospace">explorer
+default FreeFileSync opens the operating system's file browser on
+each mouse double-click by invoking &quot;<FONT FACE="Courier New, monospace">explorer
/select, &quot;%item_path%&quot;</FONT>&quot; on Windows and
&quot;<FONT FACE="Courier New, monospace">xdg-open &quot;%item_folder%&quot;</FONT>&quot;
on Linux.</FONT></P>
<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">However
-you are free to integrate other external applications into
-FreeFileSync: navigate to &quot;</FONT><FONT FACE="Tahoma, sans-serif"><I>Menu
--&gt; Advanced -&gt; Global settings: External Applications</I></FONT><FONT FACE="Tahoma, sans-serif">&quot;
-and add or replace a command string. The first entry is executed when
-double-clicking a row on main grid while all other entries are only
-available via right-click context menu. The following internal macros
-may be used:</FONT></P>
+you may integrate other external applications into FreeFileSync:
+navigate to &quot;</FONT><FONT FACE="Tahoma, sans-serif"><I>Menu -&gt;
+Advanced -&gt; Global settings: External Applications</I></FONT><FONT FACE="Tahoma, sans-serif">&quot;
+and add or replace a command. The first entry is executed when
+double-clicking a row or pressing ENTER on main grid while all other
+entries can only be accessed via the context menu shown after a
+right-click. The following internal macros are available:</FONT></P>
<P STYLE="margin-left: 1.32cm; margin-bottom: 0cm"><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6">
<P ALIGN=LEFT STYLE="margin-left: 0.79cm; margin-right: 0.98cm; margin-bottom: 0cm">
<FONT FACE="Courier New, monospace">%item_path%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-
<FONT FACE="Tahoma, sans-serif">full file or folder
name</FONT><BR>%item_folder% &nbsp;&nbsp;- <FONT FACE="Tahoma, sans-serif">folder
- part only</FONT><BR>%item2_path%&nbsp;&nbsp;&nbsp;&nbsp;- <FONT FACE="Tahoma, sans-serif">Other
- side's counterpart to %item_path%</FONT><BR>%item2_folder%&nbsp;&nbsp;-
- <FONT FACE="Tahoma, sans-serif">Other side's counterpart to
- %item_folder%</FONT></FONT></P>
+ part only</FONT><BR>%item2_path%&nbsp;&nbsp;&nbsp;&nbsp;-
+ <FONT FACE="Tahoma, sans-serif">Counterpart of %item_path% on the
+ opposite grid</FONT><BR>%item2_folder%&nbsp;&nbsp;- <FONT FACE="Tahoma, sans-serif">Counterpart
+ of %item_folder% on the opposite grid</FONT></FONT></P>
</SPAN><BR CLEAR=LEFT><BR>
</P>
<P STYLE="margin-bottom: 0cm"><BR>
diff --git a/BUILD/Help/html/RealtimeSync.html b/BUILD/Help/html/RealtimeSync.html
index f7740c09..b8a94c62 100644
--- a/BUILD/Help/html/RealtimeSync.html
+++ b/BUILD/Help/html/RealtimeSync.html
@@ -71,7 +71,7 @@ to begin monitoring.</FONT></P>
integrated into the operating system's auto start
facility:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Courier New, monospace">&quot;C:\Program
Files\FreeFileSync\RealtimeSync.exe&quot;
- &quot;C:\MyConfig.ffs_real&quot;<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Courier New, monospace">&quot;C:\Program
+ &quot;C:\SyncJob.ffs_real&quot;<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT FACE="Courier New, monospace">&quot;C:\Program
Files\FreeFileSync\RealtimeSync.exe&quot; &quot;C:\SyncJob.ffs_batch&quot;</FONT><BR>&nbsp;</FONT></P>
<LI><P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Using
RealtimeSync is not restricted to starting FreeFileSync. It can
diff --git a/BUILD/Help/html/Run as Service.html b/BUILD/Help/html/Run as Service.html
index f6329a33..ae8f57c3 100644
--- a/BUILD/Help/html/Run as Service.html
+++ b/BUILD/Help/html/Run as Service.html
@@ -3,9 +3,9 @@
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE></TITLE>
- <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.4.1 (Win32)">
<META NAME="CREATED" CONTENT="20091206;16574000">
- <META NAME="CHANGED" CONTENT="20120905;21304100">
+ <META NAME="CHANGED" CONTENT="20130126;13004654">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -41,7 +41,7 @@ file&gt;</SPAN></I></FONT></P>
<P ALIGN=LEFT STYLE="margin-left: 0.79cm; margin-right: 0.98cm; margin-bottom: 0cm">
<FONT FACE="Courier New, monospace">&quot;C:\Program
Files\FreeFileSync\RealtimeSync.exe&quot; &quot;C:\some
- folder\SyncJob.ffs_batch&quot;</FONT></P>
+ folder\SyncJob.ffs_real&quot;</FONT></P>
</SPAN><BR CLEAR=LEFT>
</P>
</UL>
@@ -52,8 +52,8 @@ file&gt;</SPAN></I></FONT></P>
should be monitoring only while a specific user is logged in: </SPAN></SPAN>Create
a new shortcut, enter the command line from above as target and
place it into the user's autostart folder.</FONT></P>
- <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/create_shortcut.png" NAME="Grafik3" ALIGN=BOTTOM BORDER=0></P>
- <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/shortcut_properties.png" NAME="Grafik4" ALIGN=BOTTOM BORDER=0></P>
+ <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/create_shortcut.png" NAME="Grafik3" ALIGN=BOTTOM WIDTH=626 HEIGHT=338 BORDER=0></P>
+ <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/shortcut_properties.png" NAME="Grafik4" ALIGN=BOTTOM WIDTH=377 HEIGHT=451 BORDER=0></P>
<P STYLE="margin-bottom: 0cm">&nbsp;</P>
<LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">RealtimeSync
should be monitoring while Windows is online irrespective of
@@ -63,7 +63,7 @@ file&gt;</SPAN></I></FONT></P>
a Batch Job</A> for an example how to add a new task. Then change
the user to run the task to &quot;SYSTEM&quot; - a special user
account always running in the background.</FONT></P>
- <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/schedule_realtimesync.png" NAME="Grafik1" ALIGN=BOTTOM BORDER=0></P>
+ <P STYLE="margin-bottom: 0cm"><IMG SRC="../img/schedule_realtimesync.png" NAME="Grafik1" ALIGN=BOTTOM WIDTH=708 HEIGHT=284 BORDER=0></P>
</OL>
<P STYLE="margin-bottom: 0cm"><BR>
</P>
diff --git a/BUILD/Help/html/Schedule a Batch Job.html b/BUILD/Help/html/Schedule a Batch Job.html
index 3f05268b..ee306e47 100644
--- a/BUILD/Help/html/Schedule a Batch Job.html
+++ b/BUILD/Help/html/Schedule a Batch Job.html
@@ -93,7 +93,7 @@ a Batch Job</FONT></FONT></H2>
<LI><P STYLE="margin-bottom: 0cm; font-weight: normal"><FONT FACE="Tahoma, sans-serif">Enter
&quot;Run:&quot; as: <FONT FACE="Courier New, monospace">&lt;FreeFileSync
installation directory&gt;\FreeFileSync.exe &lt;job
- name&gt;.ffs_batch</FONT><BR><IMG SRC="../img/ScheduleBatch.gif" NAME="Grafik2" ALIGN=BOTTOM BORDER=0><BR>&nbsp;</FONT></P>
+ name&gt;.ffs_batch</FONT><BR><IMG SRC="../img/ScheduleBatch.png" NAME="Grafik2" ALIGN=BOTTOM BORDER=0><BR>&nbsp;</FONT></P>
</UL>
<LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Ubuntu
Linux Gnome-schedule:</B></FONT></P>
diff --git a/BUILD/Help/img/ScheduleBatch.gif b/BUILD/Help/img/ScheduleBatch.gif
deleted file mode 100644
index 20d27d6d..00000000
--- a/BUILD/Help/img/ScheduleBatch.gif
+++ /dev/null
Binary files differ
diff --git a/BUILD/Help/img/ScheduleBatch.png b/BUILD/Help/img/ScheduleBatch.png
new file mode 100644
index 00000000..c991d1fd
--- /dev/null
+++ b/BUILD/Help/img/ScheduleBatch.png
Binary files differ
diff --git a/BUILD/Help/img/create_shortcut.png b/BUILD/Help/img/create_shortcut.png
index fba73ec1..2c42f3a1 100644
--- a/BUILD/Help/img/create_shortcut.png
+++ b/BUILD/Help/img/create_shortcut.png
Binary files differ
diff --git a/BUILD/Help/img/schedule_realtimesync.png b/BUILD/Help/img/schedule_realtimesync.png
index 285804b4..ac1e2a80 100644
--- a/BUILD/Help/img/schedule_realtimesync.png
+++ b/BUILD/Help/img/schedule_realtimesync.png
Binary files differ
diff --git a/BUILD/Help/img/shortcut_properties.png b/BUILD/Help/img/shortcut_properties.png
index c801f6d3..1e06b617 100644
--- a/BUILD/Help/img/shortcut_properties.png
+++ b/BUILD/Help/img/shortcut_properties.png
Binary files differ
diff --git a/BUILD/Help/img/win7scheduler.png b/BUILD/Help/img/win7scheduler.png
index 08314d16..93f1e020 100644
--- a/BUILD/Help/img/win7scheduler.png
+++ b/BUILD/Help/img/win7scheduler.png
Binary files differ
diff --git a/BUILD/Languages/arabic.lng b/BUILD/Languages/arabic.lng
new file mode 100644
index 00000000..7a3ee9b1
--- /dev/null
+++ b/BUILD/Languages/arabic.lng
@@ -0,0 +1,1421 @@
+<header>
+ <language name>العربية</language name>
+ <translator>Awadh Al-Ghaamdi</translator>
+ <locale>ar</locale>
+ <flag file>arabic.png</flag file>
+ <plural forms>6</plural forms>
+ <plural definition>n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5</plural definition>
+</header>
+
+<source>Searching for folder %x...</source>
+<target>البحث عن المجلد %x...</target>
+
+<source>Items processed:</source>
+<target>معالجة العناصر:</target>
+
+<source>Items remaining:</source>
+<target>العناصر المتبقية:</target>
+
+<source>Total time:</source>
+<target>مجموع الوقت:</target>
+
+<source>Show in Explorer</source>
+<target>إظهار في مستكشف</target>
+
+<source>Open with default application</source>
+<target>فتح باستخدام التطبيق الافتراضي</target>
+
+<source>Browse directory</source>
+<target>تصفح الدليل</target>
+
+<source>Abort requested: Waiting for current operation to finish...</source>
+<target>إحباط وطلبت: في انتظار انتهاء العملية الحالية...</target>
+
+<source>Failure to create timestamp for versioning:</source>
+<target>فشل إنشاء الطابع الزمني للإصدارات:</target>
+
+<source>RealtimeSync - Automated Synchronization</source>
+<target>المزامنة التلقائية</target>
+
+<source>Error</source>
+<target>خطأ</target>
+
+<source>Select alternate comparison settings</source>
+<target>حدد إعدادات المقارنة البديل</target>
+
+<source>Select alternate synchronization settings</source>
+<target>حدد إعدادات المزامنة البديل</target>
+
+<source>Filter is active</source>
+<target>عامل التصفية نشط</target>
+
+<source>No filter selected</source>
+<target>لا يوجد عامل تصفية مختارة</target>
+
+<source>Remove alternate settings</source>
+<target>إزالة إعدادات البديل</target>
+
+<source>Clear filter settings</source>
+<target>مسح إعدادات عامل التصفية</target>
+
+<source>Save as batch job</source>
+<target>حفظ كمهمة دفعية</target>
+
+<source>Comparison settings</source>
+<target>إعدادات المقارنة</target>
+
+<source>Synchronization settings</source>
+<target>إعدادات المزامنة</target>
+
+<source>About</source>
+<target>حول</target>
+
+<source>Confirm</source>
+<target>تأكيد</target>
+
+<source>Configure filter</source>
+<target>تكوين عامل تصفية</target>
+
+<source>Global settings</source>
+<target>الإعدادات العامة</target>
+
+<source>Find</source>
+<target>بحث</target>
+
+<source>Select time span</source>
+<target>حدد الفترة الزمنية</target>
+
+<source>Invalid command line:</source>
+<target>سطر الأوامر غير صالح:</target>
+
+<source>Info</source>
+<target>معلومات</target>
+
+<source>Warning</source>
+<target>تحذير</target>
+
+<source>Fatal Error</source>
+<target>خطأ فادح</target>
+
+<source>Windows Error Code %x:</source>
+<target>رمز خطأ Windows %x:</target>
+
+<source>Linux Error Code %x:</source>
+<target>رمز الخطأ لينكس %x:</target>
+
+<source>Cannot resolve symbolic link %x.</source>
+<target>لا يمكن حل الارتباط الرمزي %x.</target>
+
+<source>%x MB</source>
+<target>%x مب</target>
+
+<source>%x KB</source>
+<target>%x ك. بايت</target>
+
+<source>%x GB</source>
+<target>%x GB</target>
+
+<source>
+<pluralform>1 Byte</pluralform>
+<pluralform>%x Bytes</pluralform>
+</source>
+<target></target>
+
+<source>Database file %x is incompatible.</source>
+<target>ملف قاعدة البيانات %x غير متوافق.</target>
+
+<source>Initial synchronization:</source>
+<target>المزامنة الأولية:</target>
+
+<source>Database file %x does not yet exist.</source>
+<target>ملف قاعدة البيانات %x غير موجود حتى الآن.</target>
+
+<source>Database file is corrupt:</source>
+<target>ملف قاعدة البيانات معطوبة:</target>
+
+<source>Out of memory!</source>
+<target>نفاد في الذاكرة</target>
+
+<source>Cannot write file %x.</source>
+<target>لا يمكن كتابة ملف %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>لا يمكن قراءة الملف %x.</target>
+
+<source>Database files do not share a common session.</source>
+<target>عدم مشاركة ملفات قاعدة بيانات جلسة عمل مشتركة.</target>
+
+<source>An exception occurred!</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>Cannot set directory lock %x.</source>
+<target>لا يمكن تعيين الدليل قفل %x.</target>
+
+<source>
+<pluralform>1 sec</pluralform>
+<pluralform>%x sec</pluralform>
+</source>
+<target></target>
+
+<source>Error parsing file %x, row %y, column %z.</source>
+<target>حدث خطأ أثناء تحليل ملف %x، صف %y، وعمود %z.</target>
+
+<source>Scanning:</source>
+<target>المسح الضوئي:</target>
+
+<source>Encoding extended time information: %x</source>
+<target>ترميز المعلومات تمديد الوقت: %x</target>
+
+<source>
+<pluralform>[1 Thread]</pluralform>
+<pluralform>[%x Threads]</pluralform>
+</source>
+<target></target>
+
+<source>/sec</source>
+<target>/ثانية</target>
+
+<source>Cannot find file %x.</source>
+<target>لا يمكن العثور على الملف %x.</target>
+
+<source>File %x does not contain a valid configuration.</source>
+<target>لا يحتوي ملف %x تكويناً صحيحاً.</target>
+
+<source>Configuration file %x loaded partially only.</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-بت لإنشاء ملفات الظل الاحتياطية على هذا النظام.</target>
+
+<source>Cannot load file %x.</source>
+<target>لا يمكن تحميل الملف %x.</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</target>
+
+<source>Cannot read the following XML elements:</source>
+<target>لا يمكن قراءة عناصر XML التالية:</target>
+
+<source>&Open...</source>
+<target>فتح...</target>
+
+<source>Save &as...</source>
+<target>حفظ باسم...</target>
+
+<source>&Quit</source>
+<target>إنهاء</target>
+
+<source>&Program</source>
+<target>البرنامج</target>
+
+<source>&Content</source>
+<target>المحتوى</target>
+
+<source>&About</source>
+<target>حول</target>
+
+<source>&Help</source>
+<target>تعليمات</target>
+
+<source>Usage:</source>
+<target>الاستخدام:</target>
+
+<source>1. Select folders to watch.</source>
+<target>1. حدد المجلدات لمشاهدة.</target>
+
+<source>2. Enter a command line.</source>
+<target>2. إدخال سطر الأوامر.</target>
+
+<source>3. Press 'Start'.</source>
+<target>3. اضغط على 'ابدأ'.</target>
+
+<source>To get started just import a .ffs_batch file.</source>
+<target>للحصول على بدء تشغيل الاستيراد فقط ملف .ffs_batch.</target>
+
+<source>Folders to watch</source>
+<target>المجلدات لمشاهدة</target>
+
+<source>Add folder</source>
+<target>إضافة مجلد</target>
+
+<source>Remove folder</source>
+<target>إزالة مجلد</target>
+
+<source>Browse</source>
+<target>تصفح</target>
+
+<source>Select a folder</source>
+<target>حدد مجلد</target>
+
+<source>Idle time [seconds]</source>
+<target>وقت الخمول [ثانية]</target>
+
+<source>Idle time between last detected change and execution of command</source>
+<target>وقت الخمول بين آخر تغيير تم الكشف عنها وتنفيذ الأوامر</target>
+
+<source>Command line</source>
+<target>سطر الأوامر</target>
+
+<source>
+The command is triggered if:
+- files or subfolders change
+- new folders arrive (e.g. USB stick insert)
+</source>
+<target>
+يتم تشغيل الأمر إذا:
+-تغيير الملفات أو المجلدات الفرعية
+--يصل إلى المجلدات الجديدة (مثل إدراج عصا الناقل التسلسلي العام)
+</target>
+
+<source>Start</source>
+<target>بدء تشغيل</target>
+
+<source>&Retry</source>
+<target>إعادة المحاولة</target>
+
+<source>Cancel</source>
+<target>إلغاء الأمر</target>
+
+<source>Build: %x</source>
+<target>بناء: %x</target>
+
+<source>All files</source>
+<target>جميع الملفات</target>
+
+<source>&Restore</source>
+<target>استعادة</target>
+
+<source>&Exit</source>
+<target>خروج</target>
+
+<source>Monitoring active...</source>
+<target>الرصد النشط...</target>
+
+<source>Waiting for missing directories...</source>
+<target>في انتظار الدلائل مفقود...</target>
+
+<source>A folder input field is empty.</source>
+<target>حقل إدخال مجلد فارغ.</target>
+
+<source>Synchronization aborted!</source>
+<target>تم إحباط المزامنة</target>
+
+<source>Synchronization completed with errors!</source>
+<target>تزامن إكمال مع وجود خطأ!</target>
+
+<source>Synchronization completed with warnings.</source>
+<target>تزامن الانتهاء مع التحذيرات.</target>
+
+<source>Nothing to synchronize!</source>
+<target>لا شيء لمزامنة</target>
+
+<source>Synchronization completed successfully.</source>
+<target>تمت المزامنة بنجاح</target>
+
+<source>Saving log file %x...</source>
+<target>حفظ ملف السجل %x...</target>
+
+<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
+<target>اضغط على "التبديل" لحل القضايا في الحوار الرئيسي البرنامج.</target>
+
+<source>Switching to FreeFileSync main dialog...</source>
+<target>التحول إلى الحوار الرئيسي البرنامج...</target>
+
+<source>A new version of FreeFileSync is available:</source>
+<target>يتوفر إصدار جديد من البرنامج:</target>
+
+<source>Download now?</source>
+<target>تحميل الآن؟</target>
+
+<source>FreeFileSync is up to date!</source>
+<target>البرنامج هو الأحدث حتى الآن!</target>
+
+<source>Information</source>
+<target>معلومات</target>
+
+<source>Unable to connect to sourceforge.net!</source>
+<target>غير قادر على الاتصال إلى sourceforge.net!</target>
+
+<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
+<target>لم يتم العثور على رقم الإصدار الحالي من البرنامج على الإنترنت! هل تريد التحقق يدوياً؟</target>
+
+<source>Do you want FreeFileSync to automatically check for updates every week?</source>
+<target>هل تريد التحقق تلقائياً من وجود تحديثات كل أسبوع؟</target>
+
+<source>(Requires an Internet connection!)</source>
+<target>(يتطلب اتصال إنترنت)!</target>
+
+<source><Symlink></source>
+<target><Symlink></target>
+
+<source><Folder></source>
+<target><المجلد></target>
+
+<source>Full path</source>
+<target>المسار الكامل</target>
+
+<source>Name</source>
+<target>الاسم</target>
+
+<source>Relative path</source>
+<target>مسار نسبي</target>
+
+<source>Base folder</source>
+<target>المجلد الأساسي</target>
+
+<source>Size</source>
+<target>الحجم</target>
+
+<source>Date</source>
+<target>تاريخ</target>
+
+<source>Extension</source>
+<target>ملحق</target>
+
+<source>Size:</source>
+<target>الحجم:</target>
+
+<source>Date:</source>
+<target>التاريخ:</target>
+
+<source>Action</source>
+<target>عمل</target>
+
+<source>Category</source>
+<target>الفئة</target>
+
+<source>Drag && drop</source>
+<target>سحب إفلات</target>
+
+<source>Close progress dialog</source>
+<target>تقدم وثيقة الحوار</target>
+
+<source>Standby</source>
+<target>وضع الاستعداد</target>
+
+<source>Log off</source>
+<target>تسجيل الخروج</target>
+
+<source>Shut down</source>
+<target>إيقاف التشغيل</target>
+
+<source>Hibernate</source>
+<target>السبات</target>
+
+<source>&New</source>
+<target>الجديد</target>
+
+<source>&Save</source>
+<target>حفظ</target>
+
+<source>Save as &batch job...</source>
+<target>حفظ كمهمة دفعية...</target>
+
+<source>1. &Compare</source>
+<target>1-مقارنة</target>
+
+<source>2. &Synchronize</source>
+<target>2. مزامنة</target>
+
+<source>&Language</source>
+<target>اللغة</target>
+
+<source>&Global settings...</source>
+<target>الإعدادات العمومية...</target>
+
+<source>&Export file list...</source>
+<target>تصدير قائمة ملف...</target>
+
+<source>&Advanced</source>
+<target>متقدم</target>
+
+<source>&Check for new version</source>
+<target>التحقق من الإصدار الجديد</target>
+
+<source>Compare</source>
+<target>قارن</target>
+
+<source>Compare both sides</source>
+<target>المقارنة بين كلا الجانبين</target>
+
+<source>&Abort</source>
+<target>إحباط</target>
+
+<source>Synchronize</source>
+<target>مزامنة</target>
+
+<source>Start synchronization</source>
+<target>بدء تشغيل المزامنة</target>
+
+<source>Add folder pair</source>
+<target>إضافة مجلد زوج</target>
+
+<source>Remove folder pair</source>
+<target>إزالة المجلد الثاني</target>
+
+<source>Swap sides</source>
+<target>مبادلة الجانبين</target>
+
+<source>Open</source>
+<target>فتح</target>
+
+<source>Save</source>
+<target>حفظ</target>
+
+<source>Last used configurations (press DEL to remove from list)</source>
+<target>آخر استخدام تكوينات (اضغط DEL لإزالة من القائمة)</target>
+
+<source>Hide excluded items</source>
+<target>إخفاء العناصر المستبعدة</target>
+
+<source>Show filtered or temporarily excluded files</source>
+<target>عرض تمت تصفيتها أو مؤقتاً استبعاد الملفات</target>
+
+<source>Number of files and folders that will be created</source>
+<target>عدد من الملفات والمجلدات التي سيتم إنشاؤها</target>
+
+<source>Number of files that will be overwritten</source>
+<target>عدد الملفات التي سيتم الكتابة فوق</target>
+
+<source>Number of files and folders that will be deleted</source>
+<target>عدد من الملفات والمجلدات التي سيتم حذفها</target>
+
+<source>Total bytes to copy</source>
+<target>إجمالي وحدات البايت لنسخ</target>
+
+<source>Items found:</source>
+<target>العناصر التي تم العثور عليها:</target>
+
+<source>Speed:</source>
+<target>السرعة:</target>
+
+<source>Time remaining:</source>
+<target>الوقت المتبقي:</target>
+
+<source>Time elapsed:</source>
+<target>الوقت المنقضي:</target>
+
+<source>Batch job</source>
+<target>مهمة المجموعة</target>
+
+<source>Help</source>
+<target>تعليمات</target>
+
+<source>Error handling</source>
+<target>معالجة الأخطاء</target>
+
+<source>Ignore</source>
+<target>تجاهل</target>
+
+<source>Hide all error and warning messages</source>
+<target>إخفاء جميع الخطأ ورسائل تحذير</target>
+
+<source>Pop-up</source>
+<target>إطار منبثق</target>
+
+<source>Show pop-up on errors or warnings</source>
+<target>إظهار المنبثقة عن أخطاء أو تحذيرات</target>
+
+<source>Exit</source>
+<target>خروج</target>
+
+<source>Abort synchronization on first error</source>
+<target>إحباط المزامنة على الخطأ الأول</target>
+
+<source>On completion</source>
+<target>وعند الانتهاء</target>
+
+<source>Show progress dialog</source>
+<target>إظهار التقدم في الحوار</target>
+
+<source>Save log</source>
+<target>حفظ سجل</target>
+
+<source>Select folder to save log files</source>
+<target>حدد مجلداً لحفظ ملفات السجل</target>
+
+<source>Limit</source>
+<target>الحد الأقصى</target>
+
+<source>Limit maximum number of log files</source>
+<target>تقييد الحد الأقصى لعدد ملفات السجل</target>
+
+<source>Select variant</source>
+<target>حدد الخيار</target>
+
+<source>
+Files are found equal if
+ - last write time and date
+ - file size
+are the same
+</source>
+<target>
+تم العثور على ملفات متساوية إذا
+ -آخر كتابة الوقت والتاريخ
+ -حجم الملف
+هي نفسها
+</target>
+
+<source>File time and size</source>
+<target>وقت الملف والحجم</target>
+
+<source>
+Files are found equal if
+ - file content
+is the same
+</source>
+<target>
+تم العثور على ملفات متساوية إذا
+ --محتوى الملف
+هو نفسه
+</target>
+
+<source>File content</source>
+<target>محتوى الملف</target>
+
+<source>Symbolic Link handling</source>
+<target>التعامل مع ارتباط رمزي</target>
+
+<source>OK</source>
+<target>حسنا</target>
+
+<source><- Two way -></source>
+<target><- إتجاهان -></target>
+
+<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
+<target>تحديد ونشر التغييرات في كلا الجانبين باستخدام قاعدة بيانات. عمليات حذف وإعادة تسمية والصراعات هي الكشف عن تلقائياً.</target>
+
+<source>Mirror ->></source>
+<target>مرآة->></target>
+
+<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
+<target>مرآة احتياطية من المجلد الأيسر. يتم تعديل المجلد الصحيح بالضبط مطابقة المجلد الأيسر بعد المزامنة.</target>
+
+<source>Update -></source>
+<target>تحديث-></target>
+
+<source>Copy new or updated files to right folder.</source>
+<target>نسخ الملفات الجديدة أو المحدثة إلى المجلد الصحيح.</target>
+
+<source>Custom</source>
+<target>مخصص</target>
+
+<source>Configure your own synchronization rules.</source>
+<target>تكوين قواعد المزامنة الخاصة بك.</target>
+
+<source>Deletion handling</source>
+<target>التعامل مع الحذف</target>
+
+<source>Permanent</source>
+<target>الدائمة</target>
+
+<source>Delete or overwrite files permanently</source>
+<target>حذف أو الكتابة فوق الملفات بشكل دائم</target>
+
+<source>Recycle Bin</source>
+<target>سلة المحذوفات</target>
+
+<source>Use Recycle Bin for deleted and overwritten files</source>
+<target>استخدام "سلة المحذوفات" للملفات المحذوفة والكتابة</target>
+
+<source>Versioning</source>
+<target>تعيين الإصدار</target>
+
+<source>Move time-stamped files into specified folder</source>
+<target>نقل ختم الوقت الملفات في المجلد المحدد</target>
+
+<source>Naming convention:</source>
+<target>اصطلاح التسمية:</target>
+
+<source>Configuration</source>
+<target>التكوين</target>
+
+<source>Item exists on left side only</source>
+<target>العنصر موجود على الجانب الأيسر فقط</target>
+
+<source>Item exists on right side only</source>
+<target>العنصر موجود في الجانب الأيمن فقط</target>
+
+<source>Left side is newer</source>
+<target>الجانب الأيسر الأحدث</target>
+
+<source>Right side is newer</source>
+<target>الجانب الأيمن الأحدث</target>
+
+<source>Items have different content</source>
+<target>وقد عناصر المحتوى المختلفة</target>
+
+<source>Conflict/item cannot be categorized</source>
+<target>لا يمكن أن تصنف الصراع/الصنف</target>
+
+<source>Synchronizing...</source>
+<target>مزامنة...</target>
+
+<source>&Pause</source>
+<target>إيقاف مؤقت</target>
+
+<source>Source code written in C++ using:</source>
+<target>منتديات عميد التعريب :</target>
+
+<source>If you like FreeFileSync</source>
+<target>المصدر الأول لتعريب البرامج في العالم العربي</target>
+
+<source>Donate with PayPal</source>
+<target>منتديات عميد التعريب</target>
+
+<source>Many thanks for localization:</source>
+<target>شكرا جزيلا للتعريب:</target>
+
+<source>Feedback and suggestions are welcome</source>
+<target>تعليقات واقتراحات موضع ترحيب</target>
+
+<source>Homepage</source>
+<target>الصفحة الرئيسية</target>
+
+<source>FreeFileSync at Sourceforge</source>
+<target>البرنامج في سورس</target>
+
+<source>Email</source>
+<target>البريد الإلكتروني</target>
+
+<source>Published under the GNU General Public License</source>
+<target>نشر تحت رخصة جنو العمومية العامة</target>
+
+<source>Delete on both sides</source>
+<target>حذف على كلا الجانبين</target>
+
+<source>Delete on both sides even if the file is selected on one side only</source>
+<target>حذف على كلا الجانبين حتى إذا تم تحديد الملف على جانب واحد فقط</target>
+
+<source>
+Only files that match all filter settings will be synchronized.
+Note: File names must be relative to base directories!
+</source>
+<target>
+وسوف تكون متزامنة فقط الملفات التي تطابق كافة إعدادات عامل التصفية.
+ملاحظة: يجب أن تكون أسماء الملفات بالنسبة إلى قاعدة الدلائل!
+</target>
+
+<source>Include</source>
+<target>وتشمل</target>
+
+<source>Exclude</source>
+<target>استبعاد</target>
+
+<source>Time span</source>
+<target>الفترة الزمنية</target>
+
+<source>File size</source>
+<target>حجم الملف</target>
+
+<source>Minimum</source>
+<target>الحد الأدنى</target>
+
+<source>Maximum</source>
+<target>الحد الأقصى</target>
+
+<source>&Default</source>
+<target>الافتراضي</target>
+
+<source>Fail-safe file copy</source>
+<target>نسخ ملف آمنة من الفشل</target>
+
+<source>Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error.</source>
+<target>الكتابة إلى ملف مؤقت (*.ffs_tmp) أولاً، ثم إعادة تسميته. وهذا يضمن حالة متناسقة حتى في حالة حدوث خطأ فادح.</target>
+
+<source>Copy locked files</source>
+<target>نسخ الملفات المقفلة</target>
+
+<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
+<target>نسخ الملفات المشتركة أو مؤمن باستخدام "خدمة النسخ الاحتياطي لوحدة التخزين" (حقوق المسؤول يتطلب)</target>
+
+<source>Copy file access permissions</source>
+<target>نسخ أذونات الوصول إلى الملف</target>
+
+<source>Transfer file and folder permissions (Requires Administrator rights)</source>
+<target>نقل أذونات الملفات والمجلدات (حقوق المسؤول يتطلب)</target>
+
+<source>Restore hidden dialogs</source>
+<target>استعادة الحوارات الخفية</target>
+
+<source>External applications</source>
+<target>تطبيقات خارجية</target>
+
+<source>Description</source>
+<target>الوصف</target>
+
+<source>Variant</source>
+<target>البديل</target>
+
+<source>Statistics</source>
+<target>الإحصاءات</target>
+
+<source>Don't show this dialog again</source>
+<target>عدم إظهار هذا الحوار مرة أخرى</target>
+
+<source>Find what:</source>
+<target>بحث عن:</target>
+
+<source>Match case</source>
+<target>مطابقة حالة الأحرف</target>
+
+<source>&Find next</source>
+<target>بحث عن التالي</target>
+
+<source>Operation aborted!</source>
+<target>تم إحباط العملية!</target>
+
+<source>Main bar</source>
+<target>شريط الرئيسي</target>
+
+<source>Folder pairs</source>
+<target>أزواج المجلد</target>
+
+<source>Overview</source>
+<target>نظرة عامة</target>
+
+<source>Filter files</source>
+<target>تصفية الملفات</target>
+
+<source>Select view</source>
+<target>حدد طريقة العرض</target>
+
+<source>Set direction:</source>
+<target>تحديد الاتجاه:</target>
+
+<source>Exclude temporarily</source>
+<target>استبعاد مؤقتاً</target>
+
+<source>Include temporarily</source>
+<target>وتشمل مؤقتاً</target>
+
+<source>Exclude via filter:</source>
+<target>استبعاد عن طريق التصفية:</target>
+
+<source><multiple selection></source>
+<target><تحديد متعدد></target>
+
+<source>Delete</source>
+<target>حذف</target>
+
+<source>Include all</source>
+<target>وتشمل جميع</target>
+
+<source>Exclude all</source>
+<target>استبعاد الكل</target>
+
+<source>Show icons:</source>
+<target>إظهار رموز:</target>
+
+<source>Small</source>
+<target>صغيرة</target>
+
+<source>Medium</source>
+<target>متوسطة</target>
+
+<source>Large</source>
+<target>كبيرة</target>
+
+<source>Select time span...</source>
+<target>حدد الفترة الزمنية...</target>
+
+<source>Default view</source>
+<target>طريقة العرض الافتراضية</target>
+
+<source>Show "%x"</source>
+<target>إظهار "%x"</target>
+
+<source><Last session></source>
+<target><آخر جلسة></target>
+
+<source>Folder Comparison and Synchronization</source>
+<target>مقارنة بين مجلد وتزامن</target>
+
+<source>Configuration saved!</source>
+<target>حفظ التكوين!</target>
+
+<source>FreeFileSync batch</source>
+<target>دفعة البرنامج</target>
+
+<source>Never save changes</source>
+<target>ابدأ بحفظ التغييرات</target>
+
+<source>Do you want to save changes to %x?</source>
+<target>هل تريد حفظ التغييرات إلى %x؟</target>
+
+<source>Do&n't save</source>
+<target>لا تحفظ</target>
+
+<source>Configuration loaded!</source>
+<target>تحميل تكوين!</target>
+
+<source>Hide files that exist on left side only</source>
+<target>إخفاء الملفات الموجودة على الجانب الأيسر فقط</target>
+
+<source>Show files that exist on left side only</source>
+<target>إظهار الملفات الموجودة على الجانب الأيسر فقط</target>
+
+<source>Hide files that exist on right side only</source>
+<target>إخفاء الملفات الموجودة على الجانب الأيمن فقط</target>
+
+<source>Show files that exist on right side only</source>
+<target>إظهار الملفات الموجودة على الجانب الأيمن فقط</target>
+
+<source>Hide files that are newer on left</source>
+<target>إخفاء الملفات التي الأحدث على اليسار</target>
+
+<source>Show files that are newer on left</source>
+<target>إظهار الملفات التي الأحدث على اليسار</target>
+
+<source>Hide files that are newer on right</source>
+<target>إخفاء الملفات التي الأحدث في حق</target>
+
+<source>Show files that are newer on right</source>
+<target>إظهار الملفات التي الأحدث في حق</target>
+
+<source>Hide files that are equal</source>
+<target>إخفاء الملفات التي على قدم المساواة</target>
+
+<source>Show files that are equal</source>
+<target>إظهار الملفات التي على قدم المساواة</target>
+
+<source>Hide files that are different</source>
+<target>إخفاء ملفات مختلفة</target>
+
+<source>Show files that are different</source>
+<target>إظهار ملفات مختلفة</target>
+
+<source>Hide conflicts</source>
+<target>إخفاء الصراعات</target>
+
+<source>Show conflicts</source>
+<target>إظهار الصراعات</target>
+
+<source>Hide files that will be created on the left side</source>
+<target>إخفاء الملفات التي سيتم إنشاؤها على الجانب الأيسر</target>
+
+<source>Show files that will be created on the left side</source>
+<target>إظهار الملفات التي سيتم إنشاؤها على الجانب الأيسر</target>
+
+<source>Hide files that will be created on the right side</source>
+<target>إخفاء الملفات التي سيتم إنشاؤها على الجانب الأيمن</target>
+
+<source>Show files that will be created on the right side</source>
+<target>إظهار الملفات التي سيتم إنشاؤها على الجانب الأيمن</target>
+
+<source>Hide files that will be deleted on the left side</source>
+<target>إخفاء الملفات التي سيتم حذفها على الجانب الأيسر</target>
+
+<source>Show files that will be deleted on the left side</source>
+<target>إظهار الملفات التي سيتم حذفها من على الجانب الأيسر</target>
+
+<source>Hide files that will be deleted on the right side</source>
+<target>إخفاء الملفات التي سيتم حذفها على الجانب الأيمن</target>
+
+<source>Show files that will be deleted on the right side</source>
+<target>إظهار الملفات التي سيتم حذفها على الجانب الأيمن</target>
+
+<source>Hide files that will be overwritten on left side</source>
+<target>إخفاء الملفات التي سيتم الكتابة فوق على الجانب الأيسر</target>
+
+<source>Show files that will be overwritten on left side</source>
+<target>إظهار الملفات التي سيتم الكتابة فوق على الجانب الأيسر</target>
+
+<source>Hide files that will be overwritten on right side</source>
+<target>إخفاء الملفات التي سيتم الكتابة فوق الجانب الأيمن</target>
+
+<source>Show files that will be overwritten on right side</source>
+<target>إظهار الملفات التي سيتم الكتابة فوق الجانب الأيمن</target>
+
+<source>Hide files that won't be copied</source>
+<target>إخفاء الملفات التي لن يتم نسخها</target>
+
+<source>Show files that won't be copied</source>
+<target>إظهار الملفات التي لن يتم نسخها</target>
+
+<source>All folders are in sync!</source>
+<target>تكون الكل المجلدات متزامنة</target>
+
+<source>Comma separated list</source>
+<target>قائمة مفصولة بفواصل</target>
+
+<source>Legend</source>
+<target>أسطورة</target>
+
+<source>File list exported!</source>
+<target>تصدير قائمة الملف</target>
+
+<source>
+<pluralform>Object deleted successfully!</pluralform>
+<pluralform>%x objects deleted successfully!</pluralform>
+</source>
+<target></target>
+
+<source>
+<pluralform>1 directory</pluralform>
+<pluralform>%x directories</pluralform>
+</source>
+<target></target>
+
+<source>
+<pluralform>1 file</pluralform>
+<pluralform>%x files</pluralform>
+</source>
+<target></target>
+
+<source>
+<pluralform>%x of 1 row in view</pluralform>
+<pluralform>%x of %y rows in view</pluralform>
+</source>
+<target></target>
+
+<source>Ignore further errors</source>
+<target>تجاهل المزيد من الأخطاء</target>
+
+<source>&Ignore</source>
+<target>تجاهل</target>
+
+<source>&Switch</source>
+<target>رمز التبديل</target>
+
+<source>Question</source>
+<target>سؤال</target>
+
+<source>&Yes</source>
+<target>نعم</target>
+
+<source>&No</source>
+<target>لا</target>
+
+<source>Scanning...</source>
+<target>المسح الضوئي...</target>
+
+<source>Comparing content...</source>
+<target>مقارنة المحتوى...</target>
+
+<source>Copy</source>
+<target>نسخة</target>
+
+<source>Paused</source>
+<target>تم إيقاف مؤقتاً</target>
+
+<source>Initializing...</source>
+<target>شمل...</target>
+
+<source>Aborted</source>
+<target>تم إحباط</target>
+
+<source>Completed</source>
+<target>أكملت</target>
+
+<source>Continue</source>
+<target>مواصلة</target>
+
+<source>Pause</source>
+<target>إيقاف مؤقت</target>
+
+<source>Logging</source>
+<target>تسجيل الدخول</target>
+
+<source>Cannot find %x</source>
+<target>لا يمكن العثور على %x</target>
+
+<source>Inactive</source>
+<target>غير نشط</target>
+
+<source>Today</source>
+<target>اليوم</target>
+
+<source>This week</source>
+<target>هذا الأسبوع</target>
+
+<source>This month</source>
+<target>هذا الشهر</target>
+
+<source>This year</source>
+<target>هذه السنة</target>
+
+<source>Last x days</source>
+<target>الماضية X الأيام</target>
+
+<source>Byte</source>
+<target>بايت</target>
+
+<source>KB</source>
+<target>كب</target>
+
+<source>MB</source>
+<target>مب</target>
+
+<source>Filter</source>
+<target>عامل التصفية</target>
+
+<source>Direct</source>
+<target>مباشر</target>
+
+<source>Follow</source>
+<target>اتبع</target>
+
+<source>Copy NTFS permissions</source>
+<target>نسخ أذونات NTFS</target>
+
+<source>Integrate external applications into context menu. The following macros are available:</source>
+<target>دمج تطبيقات خارجية في قائمة السياق. كما تتوفر وحدات الماكرو التالية:</target>
+
+<source>- full file or folder name</source>
+<target>-اسم الملف أو المجلد كامل</target>
+
+<source>- folder part only</source>
+<target>--مجلد جزء فقط</target>
+
+<source>- Other side's counterpart to %item_path%</source>
+<target>-النظيرة الجانب الأخرى إلى %item_path %</target>
+
+<source>- Other side's counterpart to %item_folder%</source>
+<target>-النظيرة الجانب الأخرى إلى %item_folder %</target>
+
+<source>Make hidden warnings and dialogs visible again?</source>
+<target>جعل التحذيرات الخفية وحوارات مرئية مرة أخرى؟</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></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></target>
+
+<source>Leave as unresolved conflict</source>
+<target>ترك كالصراعات التي لم تحل</target>
+
+<source>Replace</source>
+<target>استبدال</target>
+
+<source>Move files and replace if existing</source>
+<target>نقل الملفات واستبدال إذا كان موجود</target>
+
+<source>Append a timestamp to each file name</source>
+<target>إلحاق طابع زمني لكل ملف اسم</target>
+
+<source>Folder</source>
+<target>مجلد</target>
+
+<source>File</source>
+<target>الملف</target>
+
+<source>YYYY-MM-DD hhmmss</source>
+<target>Hhmmss YYYY-MM-DD</target>
+
+<source>Files</source>
+<target>الملفات</target>
+
+<source>Percentage</source>
+<target>النسبة المئوية</target>
+
+<source>Cannot monitor directory %x.</source>
+<target>لا يمكن رصد الدليل %x.</target>
+
+<source>Conversion error:</source>
+<target>خطأ تحويل:</target>
+
+<source>Cannot delete file %x.</source>
+<target>لا يمكن حذف الملف %x.</target>
+
+<source>The file is locked by another process:</source>
+<target>الملف مؤمن من قبل عملية أخرى:</target>
+
+<source>Cannot move file %x to %y.</source>
+<target>لا يمكن نقل الملف %x إلى %y.</target>
+
+<source>Cannot delete directory %x.</source>
+<target>لا يمكن حذف الدليل %x.</target>
+
+<source>Cannot write file attributes of %x.</source>
+<target>لا يمكن كتابة سمات الملف من %x.</target>
+
+<source>Cannot write modification time of %x.</source>
+<target>لا يمكن كتابة وقت التعديل من %x.</target>
+
+<source>Cannot find system function %x.</source>
+<target>لا يمكن العثور على وظيفة نظام %x.</target>
+
+<source>Cannot read security context of %x.</source>
+<target>لا يمكن قراءة سياق الأمان من %x.</target>
+
+<source>Cannot write security context of %x.</source>
+<target>لا يمكن كتابة سياق الأمان من %x.</target>
+
+<source>Cannot read permissions of %x.</source>
+<target>لا يمكن قراءة أذونات %x.</target>
+
+<source>Cannot write permissions of %x.</source>
+<target>لا يمكن كتابة أذونات %x.</target>
+
+<source>Cannot create directory %x.</source>
+<target>لا يمكن إنشاء الدليل %x.</target>
+
+<source>Cannot copy symbolic link %x to %y.</source>
+<target>لا يمكن نسخ الارتباط الرمزي %x إلى %y.</target>
+
+<source>Cannot copy file %x to %y.</source>
+<target>لا يمكن نسخ الملف %x إلى %y.</target>
+
+<source>Type of item %x is not supported:</source>
+<target>نوع عنصر %x غير معتمد:</target>
+
+<source>Cannot open directory %x.</source>
+<target>لا يمكن فتح الدليل %x.</target>
+
+<source>Cannot enumerate directory %x.</source>
+<target>لا يمكن تعداد الدليل %x.</target>
+
+<source>Detected endless directory recursion.</source>
+<target>تم الكشف عن العودية الدليل التي لا نهاية لها.</target>
+
+<source>%x TB</source>
+<target>%x السل</target>
+
+<source>%x PB</source>
+<target>PB %x</target>
+
+<source>%x%</source>
+<target>%%x</target>
+
+<source>
+<pluralform>1 min</pluralform>
+<pluralform>%x min</pluralform>
+</source>
+<target></target>
+
+<source>
+<pluralform>1 hour</pluralform>
+<pluralform>%x hours</pluralform>
+</source>
+<target></target>
+
+<source>
+<pluralform>1 day</pluralform>
+<pluralform>%x days</pluralform>
+</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>
+
+<source>Cannot determine sync-direction:</source>
+<target>لا يمكن تحديد الاتجاه المزامنة:</target>
+
+<source>No change since last synchronization!</source>
+<target>أي تغيير منذ المزامنة الأخيرة</target>
+
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>إدخالات قاعدة البيانات المطابقة ليست في تزامن النظر في الإعدادات الحالية.</target>
+
+<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
+<target>الإعداد الافتراضي في الاتجاهين المزامنة: ستتم الكتابة فوق الملفات القديمة بالملفات الأحدث.</target>
+
+<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
+<target>سلة المهملات غير متوفر للمسارات التالية! سيتم حذف الملفات بشكل دائم بدلاً من ذلك:</target>
+
+<source>You can ignore this error to consider the folder as empty.</source>
+<target>يمكنك تجاهل هذا الخطأ للنظر في مجلد فارغ.</target>
+
+<source>Cannot find folder %x.</source>
+<target>لا يمكن العثور على المجلد %x.</target>
+
+<source>Directories are dependent! Be careful when setting up synchronization rules:</source>
+<target>تعتمد الدلائل! كن حذراً عند إعداد قواعد المزامنة:</target>
+
+<source>Start comparison</source>
+<target>مقارنة ابدأ</target>
+
+<source>Preparing synchronization...</source>
+<target>إعداد المزامنة...</target>
+
+<source>Conflict detected:</source>
+<target>تم الكشف عن تعارض:</target>
+
+<source>File %x has an invalid date!</source>
+<target>يحتوي الملف %x تاريخ غير صالح</target>
+
+<source>Files %x have the same date but a different size!</source>
+<target>ملفات %x بنفس التاريخ ولكن حجم مختلف</target>
+
+<source>Items differ in attributes only</source>
+<target>تختلف عناصر في سمات فقط</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>
+
+<source>Comparing files by content failed.</source>
+<target>مقارنة الملفات حسب المحتوى التي فشلت.</target>
+
+<source>Generating file list...</source>
+<target>إنشاء قائمة الملفات...</target>
+
+<source>Both sides are equal</source>
+<target>كلا الجانبين على قدم المساواة</target>
+
+<source>Copy new item to left</source>
+<target>نسخ عنصر جديد إلى اليسار</target>
+
+<source>Copy new item to right</source>
+<target>نسخ عنصر جديد إلى اليمين</target>
+
+<source>Delete left item</source>
+<target>حذف العنصر الأيسر</target>
+
+<source>Delete right item</source>
+<target>حذف البند الصحيح</target>
+
+<source>Move file on left</source>
+<target>نقل ملف على اليسار</target>
+
+<source>Move file on right</source>
+<target>نقل ملف على اليمين</target>
+
+<source>Overwrite left item</source>
+<target>الكتابة فوق العنصر الأيسر</target>
+
+<source>Overwrite right item</source>
+<target>الكتابة فوق العنصر الصحيح</target>
+
+<source>Do nothing</source>
+<target>لا تفعل شيئا</target>
+
+<source>Update attributes on left</source>
+<target>تحديث سمات على اليسار</target>
+
+<source>Update attributes on right</source>
+<target>تحديث سمات على حق</target>
+
+<source>Multiple...</source>
+<target>متعددة...</target>
+
+<source>Deleting file %x</source>
+<target>حذف الملف %x</target>
+
+<source>Deleting folder %x</source>
+<target>حذف المجلد %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>حذف الارتباط الرمزي %x</target>
+
+<source>Moving file %x to recycle bin</source>
+<target>نقل ملف %x سلة المحذوفات</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>نقل المجلد %x سلة المحذوفات</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>نقل الارتباط الرمزي %x سلة المحذوفات</target>
+
+<source>Moving file %x to %y</source>
+<target>نقل ملف %x إلى %y</target>
+
+<source>Moving folder %x to %y</source>
+<target>نقل المجلد %x إلى %y</target>
+
+<source>Moving symbolic link %x to %y</source>
+<target>نقل الارتباط الرمزي %x إلى %y</target>
+
+<source>Removing old versions...</source>
+<target>إزالة الإصدارات القديمة...</target>
+
+<source>Creating file %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>
+
+<source>Overwriting symbolic link %x</source>
+<target>الكتابة فوق الارتباط الرمزي %x</target>
+
+<source>Verifying file %x</source>
+<target>التحقق من ملف %x</target>
+
+<source>Updating attributes of %x</source>
+<target>تحديث سمات %x</target>
+
+<source>Target folder %x already existing.</source>
+<target>المجلد الهدف %x الموجودة بالفعل.</target>
+
+<source>Target folder input field must not be empty.</source>
+<target>يجب أن لا يكون الحقل الإدخال المجلد الهدف فارغة.</target>
+
+<source>Folder input field for versioning must not be empty.</source>
+<target>حقل الإدخال المجلد لتعيين الإصدار ويجب أن لا يكون فارغاً.</target>
+
+<source>Source folder %x not found.</source>
+<target>المجلد المصدر %x لم يتم العثور على.</target>
+
+<source>The following items have unresolved conflicts and will not be synchronized:</source>
+<target>البنود التالية دون حل الصراعات، وسوف لا تكون متزامنة:</target>
+
+<source>Significant difference detected:</source>
+<target>تم الكشف عن فرق كبير:</target>
+
+<source>More than 50% of the total number of files will be copied or deleted!</source>
+<target>أكثر من 50% من إجمالي عدد الملفات التي سيتم نسخها أو حذف</target>
+
+<source>Not enough free disk space available in:</source>
+<target>غير كافية مساحة القرص الحرة المتوفرة في:</target>
+
+<source>Required:</source>
+<target>مطلوب:</target>
+
+<source>Available:</source>
+<target>متاح:</target>
+
+<source>A folder will be modified which is part of multiple folder pairs. Please review synchronization settings.</source>
+<target>سيتم تعديل مجلد الذي هو جزء من أزواج المجلد متعددة. الرجاء مراجعة إعدادات المزامنة.</target>
+
+<source>Left</source>
+<target>اليسار</target>
+
+<source>Right</source>
+<target>حق</target>
+
+<source>Synchronizing folder pair:</source>
+<target>مزامنة مجلد زوج:</target>
+
+<source>Generating database...</source>
+<target>إنشاء قاعدة بيانات...</target>
+
+<source>Data verification error: Source and target file have different content!</source>
+<target>بيانات التحقق خطأ: الملف المصدر والهدف يكون محتوى مختلفة</target>
+
diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng
index 57458c14..5c431691 100644
--- a/BUILD/Languages/chinese_simple.lng
+++ b/BUILD/Languages/chinese_simple.lng
@@ -31,8 +31,8 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>请求中止: 正在等待当前操作完成...</target>
-<source>Failure to create time stamp for versioning:</source>
-<target></target>
+<source>Failure to create timestamp for versioning:</source>
+<target>未能为历史版本创建时间标记</target>
<source>RealtimeSync - Automated Synchronization</source>
<target>实时同步 - 自动同步</target>
@@ -59,7 +59,7 @@
<target>清除过滤器设置</target>
<source>Save as batch job</source>
-<target></target>
+<target>另存为批处理作业</target>
<source>Comparison settings</source>
<target>比较设置</target>
@@ -269,7 +269,7 @@
<target>选择一个文件夹</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>空闲时间[秒]</target>
<source>Idle time between last detected change and execution of command</source>
<target>最后检测到改变和命令执行之间的空闲时间</target>
@@ -325,16 +325,16 @@ The command is triggered if:
<target>同步已完成但有错误.</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>同步已完成但有警告.</target>
<source>Nothing to synchronize!</source>
<target>没有什么可同步!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>同步成功完成.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>正在保存日志文件 %x...</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
<target>请按下"切换"来解决 FreeFileSync主对话框上的问题.</target>
@@ -358,7 +358,7 @@ The command is triggered if:
<target>无法链接到 Sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>当前FreeFileSync版本号未能在线找到! 要手工检查更新吗?</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>要让 FreeFileSync 保持每周检查一次更新吗?</target>
@@ -430,7 +430,7 @@ The command is triggered if:
<target>保存(&S)</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>另存为批处理作业(&b)</target>
<source>1. &Compare</source>
<target>1. 比较(&C)</target>
@@ -478,16 +478,16 @@ The command is triggered if:
<target>两侧互换</target>
<source>Open</source>
-<target></target>
+<target>打开</target>
<source>Save</source>
-<target></target>
+<target>保存</target>
<source>Last used configurations (press DEL to remove from list)</source>
<target>最后使用的配置(按DEL键将其从列表中移除)</target>
<source>Hide excluded items</source>
-<target></target>
+<target>隐藏排除项目</target>
<source>Show filtered or temporarily excluded files</source>
<target>显示已被过滤或被临时排除的文件</target>
@@ -547,13 +547,13 @@ The command is triggered if:
<target>在第一个错误时中止同步</target>
<source>On completion</source>
-<target></target>
+<target>在完成时</target>
<source>Show progress dialog</source>
<target>显示进度对话框</target>
<source>Save log</source>
-<target></target>
+<target>保存日志</target>
<source>Select folder to save log files</source>
<target>选择要保存日志文件的文件夹</target>
@@ -565,7 +565,7 @@ The command is triggered if:
<target>限制日志文件的量大个数</target>
<source>Select variant</source>
-<target></target>
+<target>选择不同方式</target>
<source>
Files are found equal if
@@ -604,7 +604,7 @@ is the same
<target>确定</target>
<source><- Two way -></source>
-<target></target>
+<target><-双向-></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
<target>使用一个数据库来识别和传播两边的改变. 删除,重命名和冲突会自动检测.</target>
@@ -640,7 +640,7 @@ is the same
<target>回收站</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>将删除和覆盖文件放到回收站</target>
<source>Versioning</source>
<target>保留历史版本</target>
@@ -649,7 +649,7 @@ is the same
<target>移动时间标记文件到指定的文件夹</target>
<source>Naming convention:</source>
-<target></target>
+<target>命名规则:</target>
<source>Configuration</source>
<target>配置</target>
@@ -678,7 +678,7 @@ is the same
<source>&Pause</source>
<target>暂停(&P)</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>源代码用如下C++工具写成:</target>
<source>If you like FreeFileSync</source>
@@ -1026,7 +1026,7 @@ Note: File names must be relative to base directories!
<target>正在比较文件内容...</target>
<source>Copy</source>
-<target></target>
+<target>复制</target>
<source>Paused</source>
<target>已暂停</target>
@@ -1101,13 +1101,13 @@ Note: File names must be relative to base directories!
<target>- 只对文件夹部分</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- 另一边的对应项到 %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- 另一边的对应项到 %item_folder%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>重新让已经隐藏的警告和对话框变为可见?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1129,22 +1129,22 @@ Note: File names must be relative to base directories!
<target>遗留为未解决的冲突</target>
<source>Replace</source>
-<target></target>
+<target>替换</target>
<source>Move files and replace if existing</source>
-<target></target>
+<target>移动文件, 若文件已存在则替换</target>
<source>Append a timestamp to each file name</source>
-<target></target>
+<target>附加时间戳到每一个文件名</target>
<source>Folder</source>
-<target></target>
+<target>文件夹</target>
<source>File</source>
-<target></target>
+<target>文件</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>YYYY-MM-DD hhmmss</target>
<source>Files</source>
<target>文件</target>
@@ -1201,7 +1201,7 @@ Note: File names must be relative to base directories!
<target>无法复制文件 %x 到 %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>%x 的类型不被支持:</target>
<source>Cannot open directory %x.</source>
<target>无法打开目录 %x.</target>
@@ -1375,7 +1375,7 @@ Note: File names must be relative to base directories!
<target>正在移动符号连接 %x 到 %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>移除旧版本</target>
<source>Creating file %x</source>
<target>正在创建文件 %x</target>
@@ -1411,7 +1411,7 @@ Note: File names must be relative to base directories!
<target>无法找到源文件夹 %x.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>如下项目有无法解决的冲突并将不会被同步:</target>
<source>Significant difference detected:</source>
<target>已侦测到显著不同:</target>
diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng
index 79391ed1..56f832e7 100644
--- a/BUILD/Languages/chinese_traditional.lng
+++ b/BUILD/Languages/chinese_traditional.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>中止請求:正在等待目前操作完成...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>無法新建時間戳記的版本控制:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -669,7 +669,7 @@ is the same
<source>&Pause</source>
<target>暫停(&P)</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>使用C++編寫的原始碼</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/croatian.lng b/BUILD/Languages/croatian.lng
index 1c5adb0d..fc01bb29 100644
--- a/BUILD/Languages/croatian.lng
+++ b/BUILD/Languages/croatian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Prekid zahtjevan: čekam da se trenutna akcija završi...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Nije moguća vremenska oznaka za varijantu</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -684,7 +684,7 @@ jednak
<source>&Pause</source>
<target>&Pauziraj</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Izvorni kod napisan u C++ uz korištenje:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng
index 4bc84b0a..dc0ee886 100644
--- a/BUILD/Languages/czech.lng
+++ b/BUILD/Languages/czech.lng
@@ -31,7 +31,7 @@
<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>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Chyba při vytvoření časové značky verzování:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -684,7 +684,7 @@ je stejný
<source>&Pause</source>
<target>&Pauza</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Zdrojový kód byl napsán kompletně v C++ pomocí:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/danish.lng b/BUILD/Languages/danish.lng
index 225019ac..5fcf5ec0 100644
--- a/BUILD/Languages/danish.lng
+++ b/BUILD/Languages/danish.lng
@@ -1,6 +1,6 @@
<header>
<language name>Dansk</language name>
- <translator>Kim Monberg</translator>
+ <translator>Regmos</translator>
<locale>da_DK</locale>
<flag file>denmark.png</flag file>
<plural forms>2</plural forms>
@@ -11,61 +11,61 @@
<target>Søger efter mappen %x...</target>
<source>Items processed:</source>
-<target>Enheder behandlet:</target>
+<target>Emner behandlet:</target>
<source>Items remaining:</source>
-<target>Enheder tilbage:</target>
+<target>Emner tilbage:</target>
<source>Total time:</source>
<target>Samlet tid:</target>
<source>Show in Explorer</source>
-<target>Vis i Explorer</target>
+<target>Åben filplacering</target>
<source>Open with default application</source>
-<target>Åben med standard program</target>
+<target>Åben med standardprogram</target>
<source>Browse directory</source>
-<target>Gennemse Bibliotek</target>
+<target>Gennemse mappe</target>
<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Afbrydelse: Venter på nuværende opgave afsluttes...</target>
+<target>Afbrydelse: Venter på aktuel opgave afsluttes...</target>
-<source>Failure to create time stamp for versioning:</source>
-<target></target>
+<source>Failure to create timestamp for versioning:</source>
+<target>Kunne ikke oprette versioneringstid:</target>
<source>RealtimeSync - Automated Synchronization</source>
-<target>RealtimeSynk - Automatisk Synkronisering</target>
+<target>Realtids synk - automatisk synkronisering</target>
<source>Error</source>
<target>Fejl</target>
<source>Select alternate comparison settings</source>
-<target>Vælg alternative sammenlignings indstillinger</target>
+<target>Tilpas analyse</target>
<source>Select alternate synchronization settings</source>
-<target>Vælg alternative indstillinger</target>
+<target>Tilpas synkronisering</target>
<source>Filter is active</source>
-<target>Filter er aktivt</target>
+<target>Aktivt filter</target>
<source>No filter selected</source>
<target>Intet filter valgt</target>
<source>Remove alternate settings</source>
-<target>Fjern alternative indstillinger</target>
+<target>Fjern tilpassede indstillinger</target>
<source>Clear filter settings</source>
-<target>Ryd filter indstillinger</target>
+<target>Nulstil filter</target>
<source>Save as batch job</source>
-<target></target>
+<target>Gem som batchfil</target>
<source>Comparison settings</source>
-<target>Sammenlignings indstillinger</target>
+<target>Analyseindstillinger</target>
<source>Synchronization settings</source>
-<target>Synkroniserings indstillinger</target>
+<target>Synkroniseringsindstillinger</target>
<source>About</source>
<target>Om</target>
@@ -77,13 +77,13 @@
<target>Indstil filter</target>
<source>Global settings</source>
-<target>Fælles indstillinger</target>
+<target>Programindstillinger</target>
<source>Find</source>
-<target>Find</target>
+<target>Søg</target>
<source>Select time span</source>
-<target>Vælg tids område</target>
+<target>Vælg tidsinterval</target>
<source>Invalid command line:</source>
<target>Ugyldig kommando:</target>
@@ -95,16 +95,16 @@
<target>Advarsel</target>
<source>Fatal Error</source>
-<target>Uoprettelig Fejl</target>
+<target>Fatal fejl</target>
<source>Windows Error Code %x:</source>
-<target>Windows Fejl kode %x:</target>
+<target>Windows fejlkode %x:</target>
<source>Linux Error Code %x:</source>
-<target>Linux Fejl kode %x:</target>
+<target>Linux fejlkode %x:</target>
<source>Cannot resolve symbolic link %x.</source>
-<target>Kan ikke følge linket %x.</target>
+<target>Kan ikke følge symlinket %x.</target>
<source>%x MB</source>
<target>%x MB</target>
@@ -120,48 +120,48 @@
<pluralform>%x Bytes</pluralform>
</source>
<target>
-<pluralform>1 Byte</pluralform>
-<pluralform>%x Bytes</pluralform>
+<pluralform>1 byte</pluralform>
+<pluralform>%x bytes</pluralform>
</target>
<source>Database file %x is incompatible.</source>
-<target>Database filen %x er ikke kompatibel.</target>
+<target>Databasefilen %x er inkompatibel.</target>
<source>Initial synchronization:</source>
-<target>Indledende synkronisering:</target>
+<target>Forbereder synkronisering:</target>
<source>Database file %x does not yet exist.</source>
-<target>Database filen %x findes ikke.</target>
+<target>Databasefilen %x findes ikke.</target>
<source>Database file is corrupt:</source>
-<target>Database filen er ødelagt:</target>
+<target>Databasefilen er ødelagt:</target>
<source>Out of memory!</source>
-<target>Ude af hukommelse!</target>
+<target>Ikke nok hukommelse!</target>
<source>Cannot write file %x.</source>
-<target>Kan ikke skrive filen %x.</target>
+<target>Kan ikke oprette filen %x.</target>
<source>Cannot read file %x.</source>
<target>Kan ikke læse filen %x.</target>
<source>Database files do not share a common session.</source>
-<target>Database filen kan ikke deles.</target>
+<target>Databasefiler kan ikke dele handling.</target>
<source>An exception occurred!</source>
-<target>En undtagelse er opstået!</target>
+<target>Undtagelse opstod!</target>
<source>Cannot read file attributes of %x.</source>
-<target>Kan ikke læse fil attributterne på %x.</target>
+<target>Kan ikke læse filattributterne på %x.</target>
<source>Cannot get process information.</source>
-<target>Kan ikke lave informationer over processen.</target>
+<target>Kan ikke hente procesinformation.</target>
<source>Waiting while directory is locked (%x)...</source>
-<target>Venter mens biblioteket er låst (%x)...</target>
+<target>Venter mens mappe låses (%x)...</target>
<source>Cannot set directory lock %x.</source>
-<target>Kan ikke låse biblioteket %x.</target>
+<target>Kan ikke låse mappen %x.</target>
<source>
<pluralform>1 sec</pluralform>
@@ -173,21 +173,21 @@
</target>
<source>Error parsing file %x, row %y, column %z.</source>
-<target>Fejl i videregivelse af filen %x, række %y, kolonne %z.</target>
+<target>Behandlingsfejl i filen %x, række %y, kolonne %z.</target>
<source>Scanning:</source>
<target>Skanner:</target>
<source>Encoding extended time information: %x</source>
-<target>Finder udvidet tids information: %x</target>
+<target>Opretter udvidet tidsinformation: %x</target>
<source>
<pluralform>[1 Thread]</pluralform>
<pluralform>[%x Threads]</pluralform>
</source>
<target>
-<pluralform>[1 Tråd]</pluralform>
-<pluralform>[%x Tråde]</pluralform>
+<pluralform>[1 tråd]</pluralform>
+<pluralform>[%x tråde]</pluralform>
</target>
<source>/sec</source>
@@ -197,67 +197,67 @@
<target>Kan ikke finde filen %x.</target>
<source>File %x does not contain a valid configuration.</source>
-<target>%x indeholder ikke en gyldig konfiguration.</target>
+<target>%x indeholder ikke gyldige indstillinger.</target>
<source>Configuration file %x loaded partially only.</source>
-<target>Konfigurationsfilen %x er kun delvist hentet.</target>
+<target>Indstillingsfilen %x er kun delvist indlæst.</target>
<source>Cannot access Volume Shadow Copy Service.</source>
-<target>Kan ikke få adgang til Drev Kopi Servicen.</target>
+<target>Kan ikke opnå adgang til VVS.</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>
+<target>Brug FreeFileSync 64-bit til at lave VVS kopier på dette system.</target>
<source>Cannot load file %x.</source>
-<target>Kan ikke læse filen %x.</target>
+<target>Kan ikke indlæse filen %x.</target>
<source>Path %x does not contain a volume name.</source>
-<target>Stien %x indeholder ikke et drev navn.</target>
+<target>Stien %x indeholder ikke et drevnavn.</target>
<source>Volume name %x not part of file name %y!</source>
-<target>Drev navn %x ikke en del af filnavn %y!</target>
+<target>Drevnavn %x findes ikke i filnavnet %y!</target>
<source>Cannot read the following XML elements:</source>
<target>Kan ikke læse følgende XML emner:</target>
<source>&Open...</source>
-<target>&Åben...</target>
+<target>Åben...</target>
<source>Save &as...</source>
-<target>Gem &som...</target>
+<target>Gem som...</target>
<source>&Quit</source>
-<target>&Afslut</target>
+<target>Afslut</target>
<source>&Program</source>
-<target>&Program</target>
+<target>Filer</target>
<source>&Content</source>
-<target>&Indhold</target>
+<target>Åben hjælp</target>
<source>&About</source>
-<target>&Om</target>
+<target>Om</target>
<source>&Help</source>
-<target>&Hjælp</target>
+<target>Hjælp</target>
<source>Usage:</source>
-<target>Forbrug:</target>
+<target>Gør sådan:</target>
<source>1. Select folders to watch.</source>
-<target>1. Vælg mappe at overvåge.</target>
+<target>1. Vælg mapper til jobbet.</target>
<source>2. Enter a command line.</source>
-<target>2. Skriv en kommando linje.</target>
+<target>2. Angiv en kommando.</target>
<source>3. Press 'Start'.</source>
-<target>3. Tryk 'Start'.</target>
+<target>3. Klik 'Start'.</target>
<source>To get started just import a .ffs_batch file.</source>
-<target>Importer en .ffs_batch for at komme igang.</target>
+<target>Importer en .ffs_batchfil (Filer > Åben...) for at komme igang.</target>
<source>Folders to watch</source>
-<target>Mapper der overvåges</target>
+<target>Jobbets mapper</target>
<source>Add folder</source>
<target>Tilføj mappe</target>
@@ -272,13 +272,13 @@
<target>Vælg en mappe</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Køres når computeren har ledige resourcer i [sek.]</target>
<source>Idle time between last detected change and execution of command</source>
-<target>Tid imellem sidste ændring og udførelse</target>
+<target>Tid imellem sidst fundne ændring og udførsel</target>
<source>Command line</source>
-<target>Kommando linje</target>
+<target>Kommando</target>
<source>
The command is triggered if:
@@ -288,65 +288,65 @@ The command is triggered if:
<target>
Kommandoen udføres hvis:
- filer eller undermapper ændres
-- nye mapper ankommer (Hvis en USB nøgle sættes til)
+- nye mapper findes (f.eks USB nøgle)
</target>
<source>Start</source>
<target>Start</target>
<source>&Retry</source>
-<target>&Prøv igen</target>
+<target>Prøv igen</target>
<source>Cancel</source>
-<target>Anuller</target>
+<target>Annuller</target>
<source>Build: %x</source>
-<target>Build: %x</target>
+<target>Udgivet: %x</target>
<source>All files</source>
<target>Alle filer</target>
<source>&Restore</source>
-<target>&Gendan</target>
+<target>Vis vindue</target>
<source>&Exit</source>
-<target>&Afslut</target>
+<target>Luk</target>
<source>Monitoring active...</source>
-<target>Overvågning aktiv...</target>
+<target>Overvågning kører...</target>
<source>Waiting for missing directories...</source>
-<target>Venter på manglende biblioteker...</target>
+<target>Venter på manglende mapper...</target>
<source>A folder input field is empty.</source>
-<target>Et mappe felt er tomt.</target>
+<target>Der findes et udefineret mappevalg.</target>
<source>Synchronization aborted!</source>
<target>Synkronisering afbrudt!</target>
<source>Synchronization completed with errors!</source>
-<target>Synkronisering afsluttet med fejl!</target>
+<target>Synkronisering gennemført med fejl!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>Synkronisering gennemført med advarsel</target>
<source>Nothing to synchronize!</source>
-<target>Intet at synkronisere!</target>
+<target>Alt er synkroniseret!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>Synkronisering gennemført</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Gemmer rapport %x...</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
-<target>Tryk "Skift" for at løse problemer i hoved vinduet.</target>
+<target>Klik "Skift" for at løse problemerne fra hovedvinduet.</target>
<source>Switching to FreeFileSync main dialog...</source>
-<target>Skift til hoved vinduet...</target>
+<target>Skifter til hovedvindue...</target>
<source>A new version of FreeFileSync is available:</source>
-<target>En ny version af FreeFilesyns er tilgængelig:</target>
+<target>Opdatering tilgængelig:</target>
<source>Download now?</source>
<target>Download nu?</target>
@@ -358,16 +358,16 @@ Kommandoen udføres hvis:
<target>Information</target>
<source>Unable to connect to sourceforge.net!</source>
-<target>Kan ikke forbinde til sourceforge.net!</target>
+<target>Kan ikke kontakte sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>Den aktuelle version blev ikke fundet! Vil du kontrollere manuelt</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
-<target>Skal FreeFileSync automatisk checke efter opdateringer hver uge?</target>
+<target>Skal FreeFileSync søge efter opdateringer en gang om ugen?</target>
<source>(Requires an Internet connection!)</source>
-<target>(Kræver en Internet forbindelse!)</target>
+<target>(kræver internetforbindelse!)</target>
<source><Symlink></source>
<target><Symlink></target>
@@ -376,16 +376,16 @@ Kommandoen udføres hvis:
<target><Mappe></target>
<source>Full path</source>
-<target>Fuld Sti</target>
+<target>Fuld sti</target>
<source>Name</source>
<target>Navn</target>
<source>Relative path</source>
-<target>Filsti</target>
+<target>Relativ sti</target>
<source>Base folder</source>
-<target>Grund mappe</target>
+<target>Hovedmappe</target>
<source>Size</source>
<target>Størrelse</target>
@@ -394,10 +394,10 @@ Kommandoen udføres hvis:
<target>Dato</target>
<source>Extension</source>
-<target>Udvidelse</target>
+<target>Filtype</target>
<source>Size:</source>
-<target>Størelse:</target>
+<target>Størrelse:</target>
<source>Date:</source>
<target>Dato:</target>
@@ -406,13 +406,13 @@ Kommandoen udføres hvis:
<target>Handling</target>
<source>Category</source>
-<target>Kategori</target>
+<target>Status</target>
<source>Drag && drop</source>
-<target>Træk && slip</target>
+<target>Træk emner hertil</target>
<source>Close progress dialog</source>
-<target>Luk dialog boksen</target>
+<target>Luk dialogen</target>
<source>Standby</source>
<target>Standby</target>
@@ -427,43 +427,43 @@ Kommandoen udføres hvis:
<target>Dvale</target>
<source>&New</source>
-<target>&Ny</target>
+<target>Ny</target>
<source>&Save</source>
-<target>&Gem</target>
+<target>Gem</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Gem som batchfil</target>
<source>1. &Compare</source>
-<target>1. &Sammenlign</target>
+<target>1. Analyser</target>
<source>2. &Synchronize</source>
-<target>2. &Synkroniser</target>
+<target>2. Synkroniser</target>
<source>&Language</source>
-<target>&Sprog</target>
+<target>Sprog</target>
<source>&Global settings...</source>
-<target>&Fælles indstillinger...</target>
+<target>Programindstillinger...</target>
<source>&Export file list...</source>
-<target>&Eksporter fil liste...</target>
+<target>Eksporter filliste...</target>
<source>&Advanced</source>
-<target>&Avanceret</target>
+<target>Indstillinger</target>
<source>&Check for new version</source>
-<target>&Kig efter ny version</target>
+<target>Søg efter opdatering</target>
<source>Compare</source>
-<target>Sammenlign</target>
+<target>Analyser</target>
<source>Compare both sides</source>
-<target>Sammenlign begge sider</target>
+<target>Analyser begge sider</target>
<source>&Abort</source>
-<target>&Afbryd</target>
+<target>Afbryd</target>
<source>Synchronize</source>
<target>Synkroniser</target>
@@ -472,103 +472,103 @@ Kommandoen udføres hvis:
<target>Start synkronisering</target>
<source>Add folder pair</source>
-<target>Tilføj mappe par</target>
+<target>Tilføj mappepar</target>
<source>Remove folder pair</source>
-<target>Fjern mappe par</target>
+<target>Fjern mappepar</target>
<source>Swap sides</source>
-<target>Byt sider</target>
+<target>Byt side</target>
<source>Open</source>
-<target></target>
+<target>Åben</target>
<source>Save</source>
-<target></target>
+<target>Gem job</target>
<source>Last used configurations (press DEL to remove from list)</source>
-<target>Senest brugte konfigurationer (tryk DEL for at fjerne fra listen)</target>
+<target>Senest brugte konfigurationer (tast DEL for at slette)</target>
<source>Hide excluded items</source>
-<target></target>
+<target>Skjul ekskluderede emner</target>
<source>Show filtered or temporarily excluded files</source>
-<target>Vis filtrerede eller midlertidigt afviste filer</target>
+<target>Vis filtrerede eller midlertidigt ekskluderede filer</target>
<source>Number of files and folders that will be created</source>
-<target>Antallet af filer og mapper der vil blive oprettet</target>
+<target>Antal filer og mapper der oprettes</target>
<source>Number of files that will be overwritten</source>
-<target>Antal filer der vil blive overskrevet</target>
+<target>Antal filer der overskrives</target>
<source>Number of files and folders that will be deleted</source>
-<target>Antal filer og mapper der vil blive slettet</target>
+<target>Antal filer og mapper der slettes</target>
<source>Total bytes to copy</source>
-<target>Samlet antal bytes der skal kopieres</target>
+<target>Antal bytes der kopieres</target>
<source>Items found:</source>
-<target>Enheder fundet:</target>
+<target>Emner fundet:</target>
<source>Speed:</source>
<target>Hastighed:</target>
<source>Time remaining:</source>
-<target>Tid tilbage:</target>
+<target>Resterende tid:</target>
<source>Time elapsed:</source>
-<target>Tid forbrugt:</target>
+<target>Brugt tid:</target>
<source>Batch job</source>
-<target>Batch job</target>
+<target>Batchfil</target>
<source>Create a batch file to automate synchronization. Double-click this file or schedule in your system's task planner: FreeFileSync.exe <job name>.ffs_batch</source>
-<target>Opret en batch fil for at automatiserer synkronisering. Dobbelt-klik på denne fil eller planlæg den i dit systems opgavestyring: FreeFileSync.exe <opgave navn>.ffs_batch</target>
+<target>Opret en batchfil til automatisk synkronisering. Dobbeltklik på filen eller brug systemets opgavestyring: FreeFileSync.exe <opgave navn>.ffs_batch</target>
<source>Help</source>
<target>Hjælp</target>
<source>Error handling</source>
-<target>Fejl håndtering</target>
+<target>Fejlhåndtering</target>
<source>Ignore</source>
<target>Ignorer</target>
<source>Hide all error and warning messages</source>
-<target>Skjul beskeder om fejl og advarsler</target>
+<target>Skjul fejlbeskeder og advarsler</target>
<source>Pop-up</source>
-<target>Pop-up</target>
+<target>Besked</target>
<source>Show pop-up on errors or warnings</source>
-<target>Vis pop-up ved fejl eller advarsler</target>
+<target>Vis fejlbeskeder og advarsler</target>
<source>Exit</source>
-<target>Afslut</target>
+<target>Luk</target>
<source>Abort synchronization on first error</source>
<target>Stop synkronisering ved første fejl</target>
<source>On completion</source>
-<target></target>
+<target>Ved gennemført</target>
<source>Show progress dialog</source>
-<target>Vis dialog boks</target>
+<target>Vis fremskridt</target>
<source>Save log</source>
-<target></target>
+<target>Gem rapport</target>
<source>Select folder to save log files</source>
-<target>Vælg destinations mappe til log filer</target>
+<target>Vælg mappe til rapporter</target>
<source>Limit</source>
-<target>Grænse</target>
+<target>Antal</target>
<source>Limit maximum number of log files</source>
-<target>Maksimale antal log filer</target>
+<target>Begræns antal rapporter</target>
<source>Select variant</source>
-<target></target>
+<target>Vælg type</target>
<source>
Files are found equal if
@@ -577,14 +577,14 @@ Files are found equal if
are the same
</source>
<target>
-Filer bliver set som ens hvis
- - sidst skrevne tid og dato
- - fil størrelse
-er ens
+Filer betragtes som ens hvis
+ - senest ændret
+ - filstørrelse
+er identisk
</target>
<source>File time and size</source>
-<target>Fil tid og størrelse</target>
+<target>Størrelse og tid</target>
<source>
Files are found equal if
@@ -592,46 +592,46 @@ Files are found equal if
is the same
</source>
<target>
-Filer er ens hvis
- - fil indhold
-er det samme
+Filer betragtes som ens hvis
+ - filindhold
+er identisk
</target>
<source>File content</source>
-<target>Fil indhold</target>
+<target>Indhold</target>
<source>Symbolic Link handling</source>
-<target>Link håndtering</target>
+<target>Symlink håndtering</target>
<source>OK</source>
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target>< Tovejs ></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
-<target>find ændringer på begge sider via. database. Sletninger, omdøbninger og konflikter bliver automatisk fundet.</target>
+<target>Find og udbred ændringer på begge sider via en database. Sletninger, omdøbninger og konflikter opdages automatisk.</target>
<source>Mirror ->></source>
-<target>Spejl ->></target>
+<target>Spejling >></target>
<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
-<target>Spejling af venstre mappe. Højre mappe tilpasses så den ligner den venstre efter synkronisering.</target>
+<target>Spejl venstre mappe. Efter synkronisering er højre mappe en kopi af venstre.</target>
<source>Update -></source>
-<target>Opdater -></target>
+<target>Opdater ></target>
<source>Copy new or updated files to right folder.</source>
-<target>Kopier nye eller opdaterede filer til højre mappe.</target>
+<target>Kopier nye og opdaterede filer til højre mappe.</target>
<source>Custom</source>
-<target>Brugerdefineret</target>
+<target>Tilpasset</target>
<source>Configure your own synchronization rules.</source>
-<target>Konfigurer dine egne synkroniserings regler.</target>
+<target>Opret dine egne synkroniseringsregler.</target>
<source>Deletion handling</source>
-<target>Slette håndtering</target>
+<target>Sletning</target>
<source>Permanent</source>
<target>Permanent</target>
@@ -640,61 +640,61 @@ er det samme
<target>Slet eller overskriv filer permanent</target>
<source>Recycle Bin</source>
-<target>Skralsespand</target>
+<target>Papirkurv</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Slettede og overskrevne filer flyttes til papirkurv</target>
<source>Versioning</source>
<target>Versionering</target>
<source>Move time-stamped files into specified folder</source>
-<target>Flyt tids-stemplede filer til den valgte mappe</target>
+<target>Flyt tidsstemplede filer til valgte mappe</target>
<source>Naming convention:</source>
-<target></target>
+<target>Navneregler:</target>
<source>Configuration</source>
-<target>Konfiguration</target>
+<target>Indstilling</target>
<source>Item exists on left side only</source>
-<target>Enheden findes kun på venstre side</target>
+<target>Emnet findes kun på venstre side</target>
<source>Item exists on right side only</source>
-<target>Enheden findes kun på højre side</target>
+<target>Emnet findes kun på højre side</target>
<source>Left side is newer</source>
-<target>Venstre side er nyest</target>
+<target>Venstre er nyest</target>
<source>Right side is newer</source>
-<target>Højre side er nyest</target>
+<target>Højre er nyest</target>
<source>Items have different content</source>
-<target>Enhederne har forskelligt indhold</target>
+<target>Emnerne har forskelligt indhold</target>
<source>Conflict/item cannot be categorized</source>
-<target>Advarsel/enheden kan ikke kategoriseres</target>
+<target>Konflikt/ukendt emne</target>
<source>Synchronizing...</source>
<target>Synkroniserer...</target>
<source>&Pause</source>
-<target>&Pause</target>
+<target>Pause</target>
-<source>Source code written in C++ utilizing:</source>
-<target>Source code skrevet i C++:</target>
+<source>Source code written in C++ using:</source>
+<target>Kildekoden er skrevet i C++ med hjælp fra:</target>
<source>If you like FreeFileSync</source>
-<target>Hvis du kan lide FreeFileSync</target>
+<target>Er du glad for FreeFileSync</target>
<source>Donate with PayPal</source>
-<target>Doner med PayPal</target>
+<target>Donér med PayPal</target>
<source>Many thanks for localization:</source>
-<target>Mange tak for oversættelse til:</target>
+<target>Tak for oversættelse:</target>
<source>Feedback and suggestions are welcome</source>
-<target>Feedback og forslag er velkomne</target>
+<target>Kritik og forslag er meget velkomne</target>
<source>Homepage</source>
<target>Hjemmeside</target>
@@ -703,7 +703,7 @@ er det samme
<target>FreeFileSync på Sourceforge</target>
<source>Email</source>
-<target>E-mail</target>
+<target>Email</target>
<source>Published under the GNU General Public License</source>
<target>Udgivet under GNU General Public Licence</target>
@@ -712,28 +712,28 @@ er det samme
<target>Slet på begge sider</target>
<source>Delete on both sides even if the file is selected on one side only</source>
-<target>Slet på begge sider selvom der kun er valgt en side</target>
+<target>Slet på begge sider selvom selvom filen kun 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 der passer alle filtre.
-Note: Fil navne må skal passe til grund bibliotekerne!
+Synkroniserer kun filer der opfylder alle betingelser.
+Bemærk: Filnavne skal relatere til grundmapperne!
</target>
<source>Include</source>
<target>Inkluder</target>
<source>Exclude</source>
-<target>Udeluk</target>
+<target>Ekskluder</target>
<source>Time span</source>
-<target>Tidsrum</target>
+<target>Tidsinterval</target>
<source>File size</source>
-<target>Fil Størrelse</target>
+<target>Filstørrelse</target>
<source>Minimum</source>
<target>Minimum</target>
@@ -742,25 +742,25 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Maksimum</target>
<source>&Default</source>
-<target>&Standard</target>
+<target>Standard</target>
<source>Fail-safe file copy</source>
-<target>Fejlsikret fil kopiering</target>
+<target>Sikker 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å omdøb den. Dette garanterer sikkerheden selv ved en kritisk fejl.</target>
+<target>Skriv først til en midlertidig fil (*.ffs_tmp) og omdøb derefter. Dette garanterer sikkerheden selv ved fatale fejl.</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 hjælp af Drev Kopi Servicen (Kræver Administrator rettigheder)</target>
+<target>Kopier delte eller låste filer ved hjælp af VVS (kræver administrative rettigheder)</target>
<source>Copy file access permissions</source>
-<target>Kopier fil adgangs tilladelser</target>
+<target>Kopier adgangstilladelser</target>
<source>Transfer file and folder permissions (Requires Administrator rights)</source>
-<target>Overfør fil og mappe tilladelser (Kræver Administrator rettigheder)</target>
+<target>Overfør fil- og mappetilladelser (kræver administrative rettigheder)</target>
<source>Restore hidden dialogs</source>
<target>Gendan skjulte dialoger</target>
@@ -772,43 +772,43 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Beskrivelse</target>
<source>Variant</source>
-<target>Variation</target>
+<target>Jobtype</target>
<source>Statistics</source>
-<target>Statestik</target>
+<target>Statistik</target>
<source>Don't show this dialog again</source>
-<target>Vis ikke denne dialog boks igen</target>
+<target>Vis ikke igen</target>
<source>Find what:</source>
-<target>Find:</target>
+<target>Søg efter:</target>
<source>Match case</source>
-<target>Sammenlign stor og små bogstaver</target>
+<target>Versalfølsom (a/A)</target>
<source>&Find next</source>
-<target>&Find næste</target>
+<target>Find næste</target>
<source>Operation aborted!</source>
-<target>Operation afbrudt!</target>
+<target>Handling afbrudt!</target>
<source>Main bar</source>
-<target>Hoved værktøjslinjen</target>
+<target>Hovedlinie</target>
<source>Folder pairs</source>
-<target>Mappe par</target>
+<target>Mappepar</target>
<source>Overview</source>
-<target>Overblik</target>
+<target>Oversigt</target>
<source>Filter files</source>
-<target>Filter filer</target>
+<target>Filtre</target>
<source>Select view</source>
-<target>Vælg udseende</target>
+<target>Tilpas visning</target>
<source>Set direction:</source>
-<target>Sæt handlevejen:</target>
+<target>Retning:</target>
<source>Exclude temporarily</source>
<target>Ekskluder midlertidigt</target>
@@ -817,10 +817,10 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Inkluder midlertidigt</target>
<source>Exclude via filter:</source>
-<target>Ekskluder via filter:</target>
+<target>Ekskluder m. filter:</target>
<source><multiple selection></source>
-<target><flere valg></target>
+<target><vælg flere></target>
<source>Delete</source>
<target>Slet</target>
@@ -835,19 +835,19 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Vis ikoner:</target>
<source>Small</source>
-<target>Lille</target>
+<target>Små</target>
<source>Medium</source>
-<target>Mellem</target>
+<target>Medium</target>
<source>Large</source>
-<target>Stor</target>
+<target>Store</target>
<source>Select time span...</source>
-<target>Vælg tidsområde...</target>
+<target>Vælg tidsinterval...</target>
<source>Default view</source>
-<target>Standard tilstand</target>
+<target>Standardvisning</target>
<source>Show "%x"</source>
<target>Vis "%x"</target>
@@ -856,28 +856,28 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target><Sidste opgave></target>
<source>Folder Comparison and Synchronization</source>
-<target>Mappe sammenligning og synkronisering</target>
+<target>Mappeanalyse og synkronisering</target>
<source>Configuration saved!</source>
-<target>Konfiguration gemt!</target>
+<target>Indstillinger gemt!</target>
<source>FreeFileSync batch</source>
-<target>FreeFileSync batch</target>
+<target>FreeFileSync batchfil</target>
<source>Never save changes</source>
-<target>Gem aldrig ændringer</target>
+<target>Gem aldrig</target>
<source>Do you want to save changes to %x?</source>
-<target>Ønsker du at gemme ændringerne til %x?</target>
+<target>Vil du gemme ændringer i %x?</target>
<source>Do&n't save</source>
<target>Gem ikke</target>
<source>Configuration loaded!</source>
-<target>Konfiguration hentet!</target>
+<target>Indstillinger indlæst!</target>
<source>Hide files that exist on left side only</source>
-<target>Skjul filder der kun findes på venstre side</target>
+<target>Skjul filer der kun findes på venstre side</target>
<source>Show files that exist on left side only</source>
<target>Vis filer der kun findes på venstre side</target>
@@ -889,16 +889,16 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Vis filer der kun findes på højre side</target>
<source>Hide files that are newer on left</source>
-<target>Skjul filer der er nyere til venstre</target>
+<target>Skjul nyere filer på venstre side</target>
<source>Show files that are newer on left</source>
-<target>Vis filer der er nyere til venstre</target>
+<target>Vis nyere filer på venstre side</target>
<source>Hide files that are newer on right</source>
-<target>Skjul filer der er nyere til højre</target>
+<target>Skjul nyere filer på højre side</target>
<source>Show files that are newer on right</source>
-<target>Vis filer der er nyere til højre</target>
+<target>Vis nyere filer på højre side</target>
<source>Hide files that are equal</source>
<target>Skjul ens filer</target>
@@ -919,66 +919,66 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Vis konflikter</target>
<source>Hide files that will be created on the left side</source>
-<target>Skjul filer der vil blive oprettet til venstre</target>
+<target>Skjul filer der oprettes på venstre side</target>
<source>Show files that will be created on the left side</source>
-<target>Vis filer der vil blive oprettet til venstre</target>
+<target>Vis filer der oprettes på venstre side</target>
<source>Hide files that will be created on the right side</source>
-<target>Skjul filer der vil blive oprettet til højre</target>
+<target>Skjul filer der oprettes på højre side</target>
<source>Show files that will be created on the right side</source>
-<target>Vis filer der vil blive oprettet til højre</target>
+<target>Vis filer der oprettes på højre side</target>
<source>Hide files that will be deleted on the left side</source>
-<target>Skjul filer der bliver slettet til venstre</target>
+<target>Skjul filer der slettes på venstre side</target>
<source>Show files that will be deleted on the left side</source>
-<target>Vis filer der bliver slettet til venstre</target>
+<target>Vis filer der slettes på venstre side</target>
<source>Hide files that will be deleted on the right side</source>
-<target>Skjul filer der bliver slettet til højre</target>
+<target>Skjul filer der slettes på højre side</target>
<source>Show files that will be deleted on the right side</source>
-<target>Vis filer der bliver slettet til højre</target>
+<target>Vis filer der slettes på højre side</target>
<source>Hide files that will be overwritten on left side</source>
-<target>Skjul filer der bliver overskrevet til venstre</target>
+<target>Skjul filer der overskrives på venstre side</target>
<source>Show files that will be overwritten on left side</source>
-<target>Vis filer der bliver overskrevet til venstre</target>
+<target>Vis filer der overskrives på venstre side</target>
<source>Hide files that will be overwritten on right side</source>
-<target>Skjul filer der bliver overskrevet til højre</target>
+<target>Skjul filer der overskrives på højre side</target>
<source>Show files that will be overwritten on right side</source>
-<target>Vis filer der bliver overskrevet til højre</target>
+<target>Vis filer der overskrives på højre side</target>
<source>Hide files that won't be copied</source>
-<target>Skjul filer der ikke bliver kopieret</target>
+<target>Skjul filer der ikke kopieres</target>
<source>Show files that won't be copied</source>
-<target>Vis filer der ikke bliver kopieret</target>
+<target>Vis filer der ikke kopieres</target>
<source>All folders are in sync!</source>
-<target>Alle mapper er synkroniserede</target>
+<target>Alle mapper er synkrone</target>
<source>Comma separated list</source>
-<target>Komma separeret list</target>
+<target>Kommaopdelt liste</target>
<source>Legend</source>
-<target>Legend</target>
+<target>Definitioner</target>
<source>File list exported!</source>
-<target>Fil listen er eksporteret!</target>
+<target>Fillisten blev eksporteret!</target>
<source>
<pluralform>Object deleted successfully!</pluralform>
<pluralform>%x objects deleted successfully!</pluralform>
</source>
<target>
-<pluralform>Emnet er slettet!</pluralform>
-<pluralform>%x emner er slettet!</pluralform>
+<pluralform>Emnet blev slettet!</pluralform>
+<pluralform>%x emner blev slettet!</pluralform>
</target>
<source>
@@ -986,8 +986,8 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<pluralform>%x directories</pluralform>
</source>
<target>
-<pluralform>1 bibliotek</pluralform>
-<pluralform>%x biblioteker</pluralform>
+<pluralform>1 mappe</pluralform>
+<pluralform>%x mapper</pluralform>
</target>
<source>
@@ -1012,40 +1012,40 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Ignorer fremtidige fejl</target>
<source>&Ignore</source>
-<target>&Ignorer</target>
+<target>Ignorer</target>
<source>&Switch</source>
-<target>&Skift</target>
+<target>Skift</target>
<source>Question</source>
<target>Spørgsmål</target>
<source>&Yes</source>
-<target>&Ja</target>
+<target>Ja</target>
<source>&No</source>
-<target>&Nej</target>
+<target>Nej</target>
<source>Scanning...</source>
<target>Skanner...</target>
<source>Comparing content...</source>
-<target>Sammenligner indhold...</target>
+<target>Analyserer indhold...</target>
<source>Copy</source>
-<target></target>
+<target>Kopier</target>
<source>Paused</source>
<target>Pauset</target>
<source>Initializing...</source>
-<target>Initialiserer...</target>
+<target>Forbereder...</target>
<source>Aborted</source>
<target>Afbrudt</target>
<source>Completed</source>
-<target>Fuldført</target>
+<target>Gennemført</target>
<source>Continue</source>
<target>Fortsæt</target>
@@ -1054,7 +1054,7 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Pause</target>
<source>Logging</source>
-<target>Logger</target>
+<target>Rapporter</target>
<source>Cannot find %x</source>
<target>Kan ikke finde %x</target>
@@ -1099,30 +1099,30 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Kopier NTFS tilladelser</target>
<source>Integrate external applications into context menu. The following macros are available:</source>
-<target>Integrere eksterne programme. Følgende macroer er mulige:</target>
+<target>Integrer eksterne programmer i kontekstmenu. Brug følgende macroer:</target>
<source>- full file or folder name</source>
-<target>- fulde fil eller mappe navn</target>
+<target>Komplet fil- eller mappenavn</target>
<source>- folder part only</source>
-<target>- kun mappe delen</target>
+<target>Kun mappedelen</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>Modsat sides pendant til %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>Modsat sides pendant til %item_folder%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Vis skjulte advarsler og dialoger igen?</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 emnet til skraldespanden?</pluralform>
-<pluralform>Vil du flytte følgende %x emner til skraldespanden?</pluralform>
+<pluralform>Vil du flytte emnet til papirkurven?</pluralform>
+<pluralform>Vil du flytte følgende %x emner til papirkurven?</pluralform>
</target>
<source>
@@ -1135,25 +1135,25 @@ Note: Fil navne må skal passe til grund bibliotekerne!
</target>
<source>Leave as unresolved conflict</source>
-<target>Efterlad som uløste konflikter</target>
+<target>Efterlad som uløst konflikt</target>
<source>Replace</source>
-<target></target>
+<target>Erstat</target>
<source>Move files and replace if existing</source>
-<target></target>
+<target>Flyt fil og erstat eventuelt eksisterende</target>
<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Føj tidsstempel til hvert filnavn</target>
<source>Folder</source>
-<target></target>
+<target>Mappe</target>
<source>File</source>
-<target></target>
+<target>Fil</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>YYYY-MM-DD hhmmss</target>
<source>Files</source>
<target>Filer</target>
@@ -1162,10 +1162,10 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Procent</target>
<source>Cannot monitor directory %x.</source>
-<target>Kan ikke overvåge biblioteket %x.</target>
+<target>Kan ikke overvåge mappen %x.</target>
<source>Conversion error:</source>
-<target>Konverterings fejl:</target>
+<target>Konverteringsfejl:</target>
<source>Cannot delete file %x.</source>
<target>Kan ikke slette filen %x.</target>
@@ -1177,22 +1177,22 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Kan ikke flytte filen %x til %y.</target>
<source>Cannot delete directory %x.</source>
-<target>Kan ikke slette biblioteket %x.</target>
+<target>Kan ikke slette mappen %x.</target>
<source>Cannot write file attributes of %x.</source>
-<target>Kan ikke skrive fil attributter til %x.</target>
+<target>Kan ikke skrive filattributter til %x.</target>
<source>Cannot write modification time of %x.</source>
-<target>Kan ikke opdatere ændringstiden på %x.</target>
+<target>Kan ikke opdatere tidsændring på %x.</target>
<source>Cannot find system function %x.</source>
<target>Kan ikke finde systemfunktionen %x.</target>
<source>Cannot read security context of %x.</source>
-<target>Kan ikke læse sikkerhedsindstillingerne på %x.</target>
+<target>Kan ikke læse sikkerhedsindstillinger på %x.</target>
<source>Cannot write security context of %x.</source>
-<target>Kan ikke skrive sikkerhedsindstillingerne på %x.</target>
+<target>Kan ikke skrive sikkerhedsindstillinger til %x.</target>
<source>Cannot read permissions of %x.</source>
<target>Kan ikke læse tilladelserne på %x.</target>
@@ -1201,25 +1201,25 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Kan ikke skrive tilladelserne til %x.</target>
<source>Cannot create directory %x.</source>
-<target>Kan ikke oprette biblioteket %x.</target>
+<target>Kan ikke oprette mappen %x.</target>
<source>Cannot copy symbolic link %x to %y.</source>
-<target>Kan ikke kopiere linket %x til %y.</target>
+<target>Kan ikke kopiere symlinket %x til %y.</target>
<source>Cannot copy file %x to %y.</source>
<target>Kan ikke kopiere filen %x til %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>Filtypen %x understøttes ikke:</target>
<source>Cannot open directory %x.</source>
-<target>Kan ikke åbne bibliotek %x.</target>
+<target>Kan ikke åbne mappen %x.</target>
<source>Cannot enumerate directory %x.</source>
-<target>Kan ikke optælle biblioteket %x.</target>
+<target>Kan ikke optælle mappen %x.</target>
<source>Detected endless directory recursion.</source>
-<target>Opdaget en uendelig biblioteks løkke.</target>
+<target>Uendelig mappegentagelse fundet.</target>
<source>%x TB</source>
<target>%x TB</target>
@@ -1244,7 +1244,7 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<pluralform>%x hours</pluralform>
</source>
<target>
-<pluralform>1 timer</pluralform>
+<pluralform>1 time</pluralform>
<pluralform>%x timer</pluralform>
</target>
@@ -1258,46 +1258,46 @@ Note: Fil navne må skal passe til grund bibliotekerne!
</target>
<source>Cannot set privilege %x.</source>
-<target>Kan ikke sætte privilegier til %x.</target>
+<target>Kan ikke sætte %x privilegier.</target>
<source>Unable to move %x to the Recycle Bin!</source>
-<target>Ude af stand til at flytte %x til skraldespanden!</target>
+<target>Kan ikke flytte %x til papirkurv!</target>
<source>Both sides have changed since last synchronization!</source>
-<target>Begge sider er ændret siden sidste synkronisering!</target>
+<target>Begge sider ændret siden sidste synkronisering!</target>
<source>Cannot determine sync-direction:</source>
-<target>Kan ikke bestemme synkroniseringsvej:</target>
+<target>Kan ikke bestemme retning:</target>
<source>No change since last synchronization!</source>
<target>Ingen ændringer siden sidste synkronisering!</target>
<source>The corresponding database entries are not in sync considering current settings.</source>
-<target>Databasen er ikke synkroniseret i forhold til nuværende indstillinger.</target>
+<target>Databasen er ikke synkroniseret i forhold til aktuelle indstillinger.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
-<target>Sætter standard synkroniseringsvej: Gamle filer bliver overskrevet med nyere.</target>
+<target>Sætter standardretning: Gamle filer overskrives med nyere.</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
-<target>Papirkurven kan ikke bruges på følgende stier! Filerne vil blive slettet permanent i stedet for:</target>
+<target>Papirkurven kan ikke bruges på følgende stier! Filer slettes permanent:</target>
<source>You can ignore this error to consider the folder as empty.</source>
-<target>Du kan ignorere denne fejl og betegne mappen som tom.</target>
+<target>Du kan ignorere denne fejl og betragte mappen som tom.</target>
<source>Cannot find folder %x.</source>
<target>Kan ikke finde mappen %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>
+<target>Afhængige mapper! Vær forsigtig når du laver synkroniseringsregler:</target>
<source>Start comparison</source>
-<target>Start sammenligning</target>
+<target>Start analyse</target>
<source>Preparing synchronization...</source>
<target>Forbereder synkronisering...</target>
<source>Conflict detected:</source>
-<target>Konflik fundet:</target>
+<target>Konflikt fundet:</target>
<source>File %x has an invalid date!</source>
<target>Filen %x har en ugyldig dato!</target>
@@ -1306,28 +1306,28 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Filerne %x har den samme dato men forskellig størrelse!</target>
<source>Items differ in attributes only</source>
-<target>Enheder der kun har attributter til forskel</target>
+<target>Enhederne har kun attributter til forskel</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>
+<target>Symlinkene %x har samme dato men forskellige mål.</target>
<source>Comparing content of files %x</source>
<target>Sammenligner indhold af filer %x</target>
<source>Comparing files by content failed.</source>
-<target>Fejl i sammenligning af filernes indhold.</target>
+<target>Fejl ved analyse af filindhold.</target>
<source>Generating file list...</source>
-<target>Laver fil liste...</target>
+<target>Opretter filliste...</target>
<source>Both sides are equal</source>
<target>Begge sider er ens</target>
<source>Copy new item to left</source>
-<target>Kopiere nyt emne mod venstre</target>
+<target>Kopier nyt emne mod venstre</target>
<source>Copy new item to right</source>
-<target>Kopiere nyt emne mod højre</target>
+<target>Kopier nyt emne mod højre</target>
<source>Delete left item</source>
<target>Slet emne til venstre</target>
@@ -1342,10 +1342,10 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>flyt filen til højre</target>
<source>Overwrite left item</source>
-<target>Overskriv emne til venstre</target>
+<target>Overskriv venstre emne</target>
<source>Overwrite right item</source>
-<target>Overskriv emne til højre</target>
+<target>Overskriv højre emne</target>
<source>Do nothing</source>
<target>Gør intet</target>
@@ -1360,22 +1360,22 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Flere...</target>
<source>Deleting file %x</source>
-<target>Sletter fil %x</target>
+<target>Sletter filen %x</target>
<source>Deleting folder %x</source>
-<target>Sletter mappe %x</target>
+<target>Sletter mappen %x</target>
<source>Deleting symbolic link %x</source>
-<target>Sletter symbolks link %x</target>
+<target>Sletter symlinket %x</target>
<source>Moving file %x to recycle bin</source>
-<target>Flytter fil %x til papirkurven</target>
+<target>Flytter filen %x til papirkurven</target>
<source>Moving folder %x to recycle bin</source>
<target>Flytter mappe %x til papirkurven</target>
<source>Moving symbolic link %x to recycle bin</source>
-<target>Flytter link %x til papirkurven</target>
+<target>Flytter symlinket %x til papirkurven</target>
<source>Moving file %x to %y</source>
<target>Flytter filen %x til %y</target>
@@ -1384,52 +1384,52 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Flytter mappen %x til %y</target>
<source>Moving symbolic link %x to %y</source>
-<target>Flytter linket %x til %y</target>
+<target>Flytter symlinket %x til %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Fjerner gamle udgaver...</target>
<source>Creating file %x</source>
<target>Opretter filen %x</target>
<source>Creating symbolic link %x</source>
-<target>Opretter linket %x</target>
+<target>Opretter symlinket %x</target>
<source>Creating folder %x</source>
-<target>Opretter mappe %x</target>
+<target>Opretter mappen %x</target>
<source>Overwriting file %x</source>
<target>Overskriver filen %x</target>
<source>Overwriting symbolic link %x</source>
-<target>Overskriver linket %x</target>
+<target>Overskriver symlinket %x</target>
<source>Verifying file %x</source>
-<target>Verificerer fil %x</target>
+<target>Verificerer filen %x</target>
<source>Updating attributes of %x</source>
-<target>Opdaterer attributter af %x</target>
+<target>Opdaterer attributter for %x</target>
<source>Target folder %x already existing.</source>
-<target>Destinations mappen %x eksisterer allerede.</target>
+<target>Destinationsmappen %x findes allerede.</target>
<source>Target folder input field must not be empty.</source>
-<target>Destinations mappe feltet må ikke være tomt.</target>
+<target>Destinationsmappen skal angives.</target>
<source>Folder input field for versioning must not be empty.</source>
-<target>Mappe input feltet for versionering må ikke være tomt.</target>
+<target>Mappe til versionering skal angives.</target>
<source>Source folder %x not found.</source>
-<target>Kilde mappen %x blev ikke fundet.</target>
+<target>Kildemappen %x blev ikke fundet.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>Følgende emner har uløste konflikter og synkroniseres ikke:</target>
<source>Significant difference detected:</source>
-<target>Betydelig forskel fundet:</target>
+<target>Markant forskel:</target>
<source>More than 50% of the total number of files will be copied or deleted!</source>
-<target>Mere end 50% af det samlede antal filer vil blive kopieret eller slettet!</target>
+<target>Mere end 50% af af filerne kopieres eller slettes!</target>
<source>Not enough free disk space available in:</source>
<target>Ikke nok ledig diskplads på:</target>
@@ -1441,7 +1441,7 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Tilgængeligt:</target>
<source>A folder will be modified which is part of multiple folder pairs. Please review synchronization settings.</source>
-<target>En mappe som er en del af flere mappe parringer vil blive ændret. Gennemse venligst synkroniserings indstillingerne.</target>
+<target>Der ændres en mappe der tilhører flere mappepar. Kontroller dine synkroniseringsindstillinger.</target>
<source>Left</source>
<target>Venstre</target>
@@ -1450,11 +1450,11 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<target>Højre</target>
<source>Synchronizing folder pair:</source>
-<target>Synkroniserer mappe par:</target>
+<target>Synkroniserer mappepar:</target>
<source>Generating database...</source>
<target>Opretter database...</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>
+<target>Godkendelsesfejl: Kilde- og destinationsfil har forskelligt indhold!</target>
diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng
index afe5ce0e..0aff2993 100644
--- a/BUILD/Languages/dutch.lng
+++ b/BUILD/Languages/dutch.lng
@@ -31,8 +31,8 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Bezig met afbreken: Wacht op beëindiging huidige bewerking...</target>
-<source>Failure to create time stamp for versioning:</source>
-<target></target>
+<source>Failure to create timestamp for versioning:</source>
+<target>Het creëren van een tijdsstempen voor versiebeheer is mislukt:</target>
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Geautomatiseerde Synchronisatie</target>
@@ -59,7 +59,7 @@
<target>Verwijder filterinstellingen</target>
<source>Save as batch job</source>
-<target></target>
+<target>Opslaan als batch opdracht</target>
<source>Comparison settings</source>
<target>Vergelijksinstellingen</target>
@@ -272,7 +272,7 @@
<target>Selecteer een map</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Inactiviteit [seconden]</target>
<source>Idle time between last detected change and execution of command</source>
<target>Tijd tussen de laatste gedetecteerde verandering en de uitvoering van het commando</target>
@@ -328,16 +328,16 @@ De opdracht word geactiveerd als:
<target>Synchronisatie is met fouten afgerond!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>Synchronisatie afgerond met waarschuwingen.</target>
<source>Nothing to synchronize!</source>
<target>Niets om te synchroniseren!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>Synchronisatie succesvol.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Opslaan van logbestand %x...</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>
@@ -361,7 +361,7 @@ De opdracht word geactiveerd als:
<target>Kan geen verbinding maken met sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>Het huidige FreeFileSync versienummer is niet online gevonden! Wilt u handmatig checken?</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Wilt u FreeFileSync elke week automatisch laten controleren of er een nieuwe versie is?</target>
@@ -433,7 +433,7 @@ De opdracht word geactiveerd als:
<target>O&pslaan</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Opslaan als &batch opdracht...</target>
<source>1. &Compare</source>
<target>1. &Vergelijk</target>
@@ -481,16 +481,16 @@ De opdracht word geactiveerd als:
<target>Wissel zijdes</target>
<source>Open</source>
-<target></target>
+<target>Open</target>
<source>Save</source>
-<target></target>
+<target>Opslaan</target>
<source>Last used configurations (press DEL to remove from list)</source>
<target>Laatst gebruikte instellingen (druk op DEL om iets te verwijderen)</target>
<source>Hide excluded items</source>
-<target></target>
+<target>Verberg uitgesloten bestanden</target>
<source>Show filtered or temporarily excluded files</source>
<target>Laat gefilterde of tijdelijk uitgesloten bestanden zien</target>
@@ -550,13 +550,13 @@ De opdracht word geactiveerd als:
<target>Synchronisatie stoppen bij eerste foutmelding</target>
<source>On completion</source>
-<target></target>
+<target>Na voltooiing</target>
<source>Show progress dialog</source>
<target>Toon voortgangsdialoogvenster</target>
<source>Save log</source>
-<target></target>
+<target>Logbestand opslaan</target>
<source>Select folder to save log files</source>
<target>Selecteer map om log bestanden op te slaan</target>
@@ -568,7 +568,7 @@ De opdracht word geactiveerd als:
<target>Limiteer maximaal aantal log bestanden</target>
<source>Select variant</source>
-<target></target>
+<target>Selecteer variant</target>
<source>
Files are found equal if
@@ -607,7 +607,7 @@ overeenkomt
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target><- Twee kanten op -></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
<target>Identificeer en verspreid veranderingen aan beide kanten met behulp van een database. Verwijderingen, hernoemingen en conflicten worden automatisch gedetecteerd.</target>
@@ -643,7 +643,7 @@ overeenkomt
<target>Prullenbak</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Gebruik prullenbak voor verwijderde en overschreven bestanden</target>
<source>Versioning</source>
<target>Versiebeheer</target>
@@ -652,7 +652,7 @@ overeenkomt
<target>Verplaats bestanden met tijdstempel naar specifieke map</target>
<source>Naming convention:</source>
-<target></target>
+<target>Naamgevingsconventie</target>
<source>Configuration</source>
<target>Configuratie</target>
@@ -681,7 +681,7 @@ overeenkomt
<source>&Pause</source>
<target>&Pauze</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Broncode geschreven in C++ met behulp van:</target>
<source>If you like FreeFileSync</source>
@@ -960,6 +960,9 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Show files that won't be copied</source>
<target>Toon bestanden die niet gekopiëerd zullen worden</target>
+<source>Set as default</source>
+<target></target>
+
<source>All folders are in sync!</source>
<target>Alle mappen zijn gesynchroniseerd!</target>
@@ -1033,7 +1036,7 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>Inhoud vergelijken...</target>
<source>Copy</source>
-<target></target>
+<target>Kopiëren</target>
<source>Paused</source>
<target>Gepauzeerd</target>
@@ -1108,13 +1111,13 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>- alleen het map gedeelte</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- Tegenhanger van de andere kant naar %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- Tegenhanger van de andere kant naar %item_folder%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Verborgen waarschuwingen en dialogen zichtbaar maken?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1138,22 +1141,22 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>Beschouw als onopgelost conflict</target>
<source>Replace</source>
-<target></target>
+<target>Vervangen</target>
<source>Move files and replace if existing</source>
-<target></target>
+<target>Verplaats bestanden en overschrijf bestaande bestanden</target>
<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Voeg een timestamp aan elke bestandsnaam toe</target>
<source>Folder</source>
-<target></target>
+<target>Map</target>
<source>File</source>
-<target></target>
+<target>Bestand</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>JJJJ-MM-DD hhmmss</target>
<source>Files</source>
<target>Bestanden</target>
@@ -1210,7 +1213,7 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>Kan bestand %x niet kopiëren naar %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>Type van bestand %x is niet ondersteund:</target>
<source>Cannot open directory %x.</source>
<target>Kan map %x niet openen.</target>
@@ -1387,7 +1390,7 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>Bezig met verplaatsen van snelkoppeling %x naar %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Bezig met verwijderen van oude versies...</target>
<source>Creating file %x</source>
<target>Bestand %x wordt aangemaakt</target>
@@ -1423,7 +1426,7 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<target>Bronmap %x niet gevonden.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>De volgende items hebben onopgeloste conflicten en zullen niet worden gesynchroniseerd:</target>
<source>Significant difference detected:</source>
<target>Significant verschil gedetecteerd:</target>
diff --git a/BUILD/Languages/english_uk.lng b/BUILD/Languages/english_uk.lng
index 35ee5f16..fc15752f 100644
--- a/BUILD/Languages/english_uk.lng
+++ b/BUILD/Languages/english_uk.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Abort requested: Waiting for current operation to finish...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Failure to create time stamp for versioning:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -459,18 +459,12 @@ The command is triggered if:
<source>Compare</source>
<target>Compare</target>
-<source>Compare both sides</source>
-<target>Compare both sides</target>
-
<source>&Abort</source>
<target>&Abort</target>
<source>Synchronize</source>
<target>Synchronise</target>
-<source>Start synchronization</source>
-<target>Start synchronisation</target>
-
<source>Add folder pair</source>
<target>Add folder pair</target>
@@ -480,15 +474,6 @@ The command is triggered if:
<source>Swap sides</source>
<target>Swap sides</target>
-<source>Open</source>
-<target>Open</target>
-
-<source>Save</source>
-<target>Save</target>
-
-<source>Last used configurations (press DEL to remove from list)</source>
-<target>Last used configurations (press DEL to remove from list)</target>
-
<source>Hide excluded items</source>
<target>Hide excluded items</target>
@@ -681,8 +666,8 @@ is the same
<source>&Pause</source>
<target>&Pause</target>
-<source>Source code written in C++ utilizing:</source>
-<target>Source code written in C++ utilising:</target>
+<source>Source code written in C++ using:</source>
+<target>Source code written in C++ using:</target>
<source>If you like FreeFileSync</source>
<target>If you like FreeFileSync</target>
@@ -771,6 +756,9 @@ Note: File names must be relative to base directories!
<source>Description</source>
<target>Description</target>
+<source>Start synchronization</source>
+<target>Start synchronisation</target>
+
<source>Variant</source>
<target>Variant</target>
@@ -807,6 +795,15 @@ Note: File names must be relative to base directories!
<source>Select view</source>
<target>Select view</target>
+<source>Open...</source>
+<target>Open...</target>
+
+<source>Save</source>
+<target>Save</target>
+
+<source>Compare both sides</source>
+<target>Compare both sides</target>
+
<source>Set direction:</source>
<target>Set direction:</target>
@@ -960,6 +957,9 @@ Note: File names must be relative to base directories!
<source>Show files that won't be copied</source>
<target>Show files that won't be copied</target>
+<source>Set as default</source>
+<target>Set as default</target>
+
<source>All folders are in sync!</source>
<target>All folders are in sync!</target>
@@ -973,15 +973,6 @@ Note: File names must be relative to base directories!
<target>File list exported!</target>
<source>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</source>
-<target>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</target>
-
-<source>
<pluralform>1 directory</pluralform>
<pluralform>%x directories</pluralform>
</source>
@@ -1137,15 +1128,15 @@ Note: File names must be relative to base directories!
<source>Leave as unresolved conflict</source>
<target>Leave as unresolved conflict</target>
+<source>Append a timestamp to each file name</source>
+<target>Append a timestamp to each file name</target>
+
<source>Replace</source>
<target>Replace</target>
<source>Move files and replace if existing</source>
<target>Move files and replace if existing</target>
-<source>Append a timestamp to each file name</source>
-<target>Append a timestamp to each file name</target>
-
<source>Folder</source>
<target>Folder</target>
@@ -1278,6 +1269,27 @@ Note: File names must be relative to base directories!
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Setting default synchronisation directions: Old files will be overwritten with newer files.</target>
+<source>Checking recycle bin availability for folder %x...</source>
+<target>Checking recycle bin availability for folder %x...</target>
+
+<source>Moving file %x to recycle bin</source>
+<target>Moving file %x to recycle bin</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>Moving folder %x to recycle bin</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>Moving symbolic link %x to recycle bin</target>
+
+<source>Deleting file %x</source>
+<target>Deleting file %x</target>
+
+<source>Deleting folder %x</source>
+<target>Deleting folder %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Deleting symbolic link %x</target>
+
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</target>
@@ -1359,24 +1371,6 @@ Note: File names must be relative to base directories!
<source>Multiple...</source>
<target>Multiple...</target>
-<source>Deleting file %x</source>
-<target>Deleting file %x</target>
-
-<source>Deleting folder %x</source>
-<target>Deleting folder %x</target>
-
-<source>Deleting symbolic link %x</source>
-<target>Deleting symbolic link %x</target>
-
-<source>Moving file %x to recycle bin</source>
-<target>Moving file %x to recycle bin</target>
-
-<source>Moving folder %x to recycle bin</source>
-<target>Moving folder %x to recycle bin</target>
-
-<source>Moving symbolic link %x to recycle bin</source>
-<target>Moving symbolic link %x to recycle bin</target>
-
<source>Moving file %x to %y</source>
<target>Moving file %x to %y</target>
diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng
index b4115ad9..f5db927c 100644
--- a/BUILD/Languages/finnish.lng
+++ b/BUILD/Languages/finnish.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Keskeytys pyydetty: Odotetaan toiminnon loppumista...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Ongelma luoda aikaleimaa versionnissa:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ on sama
<source>&Pause</source>
<target>&Keskeytä</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Koodikieli on C++ käyttäen:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng
index 20fddc36..7d8e8a4f 100644
--- a/BUILD/Languages/french.lng
+++ b/BUILD/Languages/french.lng
@@ -31,7 +31,7 @@
<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>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Impossible de créer l'horodatage des versions</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ est identique
<source>&Pause</source>
<target>&Pause</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Code source écrit en C++ utilisant :</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng
index 6ca3b96b..af14bcd2 100644
--- a/BUILD/Languages/german.lng
+++ b/BUILD/Languages/german.lng
@@ -29,9 +29,9 @@
<target>Verzeichnis öffnen</target>
<source>Abort requested: Waiting for current operation to finish...</source>
-<target>Abbruch initiiert: Warte, bis aktuelle Operation beendet ist...</target>
+<target>Abbruch initiiert: Warte bis die aktuelle Operation beendet ist...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Der Zeitstempel für die Versionierung kann nicht erstellt werden:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -459,18 +459,12 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Compare</source>
<target>Vergleichen</target>
-<source>Compare both sides</source>
-<target>Beide Seiten vergleichen</target>
-
<source>&Abort</source>
<target>&Abbrechen</target>
<source>Synchronize</source>
<target>Synchronisieren</target>
-<source>Start synchronization</source>
-<target>Synchronisation starten</target>
-
<source>Add folder pair</source>
<target>Ordnerpaar hinzufügen</target>
@@ -480,15 +474,6 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Swap sides</source>
<target>Seiten vertauschen</target>
-<source>Open</source>
-<target>Öffnen</target>
-
-<source>Save</source>
-<target>Speichern</target>
-
-<source>Last used configurations (press DEL to remove from list)</source>
-<target>Zuletzt benutzte Konfigurationen (Entf-Taste löscht Einträge)</target>
-
<source>Hide excluded items</source>
<target>Ausgeschlossene Elemente verstecken</target>
@@ -681,7 +666,7 @@ gleich ist
<source>&Pause</source>
<target>&Pause</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Sourcecode in C++ geschrieben mit Hilfe von:</target>
<source>If you like FreeFileSync</source>
@@ -771,6 +756,9 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Description</source>
<target>Beschreibung</target>
+<source>Start synchronization</source>
+<target>Synchronisation starten</target>
+
<source>Variant</source>
<target>Variante</target>
@@ -807,6 +795,15 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Select view</source>
<target>Ansicht auswählen</target>
+<source>Open...</source>
+<target>Öffnen...</target>
+
+<source>Save</source>
+<target>Speichern</target>
+
+<source>Compare both sides</source>
+<target>Beide Seiten vergleichen</target>
+
<source>Set direction:</source>
<target>Setze Richtung:</target>
@@ -960,6 +957,9 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Show files that won't be copied</source>
<target>Dateien die nicht kopiert werden anzeigen</target>
+<source>Set as default</source>
+<target>Als Standard festlegen</target>
+
<source>All folders are in sync!</source>
<target>Alle Ordner sind synchron!</target>
@@ -973,15 +973,6 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<target>Dateiliste exportiert!</target>
<source>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</source>
-<target>
-<pluralform>Element erfolgreich gelöscht!</pluralform>
-<pluralform>%x Elemente erfolgreich gelöscht!</pluralform>
-</target>
-
-<source>
<pluralform>1 directory</pluralform>
<pluralform>%x directories</pluralform>
</source>
@@ -1137,15 +1128,15 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Leave as unresolved conflict</source>
<target>Als unbehandelten Konflikt belassen</target>
+<source>Append a timestamp to each file name</source>
+<target>Einen Zeitstempel an jeden Dateinamen hinzufügen</target>
+
<source>Replace</source>
<target>Ersetzen</target>
<source>Move files and replace if existing</source>
<target>Dateien verschieben und bereits vorhandene ersetzen</target>
-<source>Append a timestamp to each file name</source>
-<target>Einen Zeitstempel an jeden Dateinamen hinzufügen</target>
-
<source>Folder</source>
<target>Ordner</target>
@@ -1278,6 +1269,27 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Setze Standardwerte für Synchronisationsrichtungen: Alte Dateien werden durch neuere überschrieben.</target>
+<source>Checking recycle bin availability for folder %x...</source>
+<target>Prüfe Verfügbarkeit des Papierkorbs für Ordner %x...</target>
+
+<source>Moving file %x to recycle bin</source>
+<target>Verschiebe Datei %x in den Papierkorb</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>Verschiebe Ordner %x in den Papierkorb</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>Verschiebe Symbolischen Link %x in den Papierkorb</target>
+
+<source>Deleting file %x</source>
+<target>Lösche Datei %x</target>
+
+<source>Deleting folder %x</source>
+<target>Lösche Ordner %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Lösche Symbolischen Link %x</target>
+
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Der Papierkorb ist für die folgenden Pfade nicht verfügbar! Die Dateien werden stattdessen permanent gelöscht:</target>
@@ -1359,24 +1371,6 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Multiple...</source>
<target>Verschiedene...</target>
-<source>Deleting file %x</source>
-<target>Lösche Datei %x</target>
-
-<source>Deleting folder %x</source>
-<target>Lösche Ordner %x</target>
-
-<source>Deleting symbolic link %x</source>
-<target>Lösche Symbolischen Link %x</target>
-
-<source>Moving file %x to recycle bin</source>
-<target>Verschiebe Datei %x in den Papierkorb</target>
-
-<source>Moving folder %x to recycle bin</source>
-<target>Verschiebe Ordner %x in den Papierkorb</target>
-
-<source>Moving symbolic link %x to recycle bin</source>
-<target>Verschiebe Symbolischen Link %x in den Papierkorb</target>
-
<source>Moving file %x to %y</source>
<target>Verschiebe Datei %x nach %y</target>
diff --git a/BUILD/Languages/greek.lng b/BUILD/Languages/greek.lng
index fbdf907c..d48de099 100644
--- a/BUILD/Languages/greek.lng
+++ b/BUILD/Languages/greek.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Ζητήθηκε ματαίωση: Αναμονή για την λήξη της τρέχουσας εργασίας...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target></target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -59,7 +59,7 @@
<target>Διαγραφή όλων των ρυθμίσεων φίλτρου</target>
<source>Save as batch job</source>
-<target></target>
+<target>Αποθήκευση ως δέσμη ενεργειών</target>
<source>Comparison settings</source>
<target>Ρυθμίσεις σύγκρισης</target>
@@ -89,7 +89,7 @@
<target>Σφάλμα στη γραμμή εντολών:</target>
<source>Info</source>
-<target>Πληροφορία</target>
+<target>Πληροφορίες</target>
<source>Warning</source>
<target>Προειδοποίηση</target>
@@ -224,7 +224,7 @@
<target>Ά&νοιγμα...</target>
<source>Save &as...</source>
-<target>Απο&θήκευση ως...</target>
+<target>Αποθή&κευση ως...</target>
<source>&Quit</source>
<target>Έ&ξοδος</target>
@@ -254,7 +254,7 @@
<target>3. Πατήστε το 'Έναρξη'.</target>
<source>To get started just import a .ffs_batch file.</source>
-<target>Για να ξεκινήσετε μπορείτε απλά να εισάγεται ένα αρχείο .ffs_batch.</target>
+<target>Για να ξεκινήσετε μπορείτε απλά να εισάγετε ένα αρχείο .ffs_batch.</target>
<source>Folders to watch</source>
<target>Υποκατάλογοι που θα παρακολουθούνται</target>
@@ -272,7 +272,7 @@
<target>Επιλογή υποκαταλόγου</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Λανθάνων χρόνος [δευτερόλεπτα]</target>
<source>Idle time between last detected change and execution of command</source>
<target>Λανθάνων χρόνος μεταξύ τελευταίας αλλαγής που ανιχνεύθηκε και εκτέλεσης της εντολής</target>
@@ -328,16 +328,16 @@ The command is triggered if:
<target>Ο συγχρονισμός ολοκληρώθηκε με σφάλματα!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>Ο συγχρονισμός ολοκληρώθηκε με προειδοποιήσεις.</target>
<source>Nothing to synchronize!</source>
<target>Δεν υπάρχει τίποτα προς συγχρονισμό!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>Ο συγχρονισμός ολοκληρώθηκε επιτυχώς.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Αποθήκευση του αρχείου καταγραφής %x...</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
<target>Πατήστε "Εναλλαγή" για να επιλύσετε τα θέματα στο κεντρικό παράθυρο του FreeFileSync.</target>
@@ -361,7 +361,7 @@ The command is triggered if:
<target>Δεν είναι δυνατή η σύνδεση με το sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>Η τρέχουσα έκδοση του FreeFileSync δεν βρέθηκε στο δίκτυο! Θέλετε να την αναζητήσετε μόνος σας;</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Θέλετε το FreeFileSync να ελέγχει αυτόματα για ενημερώσεις κάθε εβδομάδα;</target>
@@ -433,7 +433,7 @@ The command is triggered if:
<target>Απο&θήκευση</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Αποθήκευση ως δέσ&μη ενεργειών...</target>
<source>1. &Compare</source>
<target>1. &Σύγκριση</target>
@@ -459,18 +459,12 @@ The command is triggered if:
<source>Compare</source>
<target>Σύγκριση</target>
-<source>Compare both sides</source>
-<target>Σύγκριση των δύο πλευρών</target>
-
<source>&Abort</source>
<target>&Άκυρο</target>
<source>Synchronize</source>
<target>Συγχρονισμός</target>
-<source>Start synchronization</source>
-<target>Έναρξη του συγχρονισμού</target>
-
<source>Add folder pair</source>
<target>Προσθήκη ζεύγους υποκαταλόγων</target>
@@ -480,17 +474,8 @@ The command is triggered if:
<source>Swap sides</source>
<target>Ανταλλαγή πλευρών</target>
-<source>Open</source>
-<target></target>
-
-<source>Save</source>
-<target></target>
-
-<source>Last used configurations (press DEL to remove from list)</source>
-<target>Διατάξεις που χρησιμοποιήθηκαν τελευταία (πατήστε DEL για διαγραφή από τη λίστα)</target>
-
<source>Hide excluded items</source>
-<target></target>
+<target>Απόκρυψη στοιχείων που εξαιρέθηκαν</target>
<source>Show filtered or temporarily excluded files</source>
<target>Εμφάνιση φιλτραρισμένων ή προσωρινά εξαιρεθέντων αρχείων</target>
@@ -550,25 +535,25 @@ The command is triggered if:
<target>Ματαίωση του συγχρονισμού με το πρώτο σφάλμα</target>
<source>On completion</source>
-<target></target>
+<target>Μετά την ολοκλήρωση</target>
<source>Show progress dialog</source>
<target>Εμφάνιση της αναφοράς προόδου</target>
<source>Save log</source>
-<target></target>
+<target>Αποθήκευση αρχείου καταγραφής</target>
<source>Select folder to save log files</source>
<target>Επιλογή υποκαταλόγου για την αποθήκευση των αρχείων καταγραφής</target>
<source>Limit</source>
-<target>Αριθμός εκδόσεων</target>
+<target>Μέγιστος αριθμός</target>
<source>Limit maximum number of log files</source>
<target>Μέγιστος αριθμός αρχείων καταγραφής</target>
<source>Select variant</source>
-<target></target>
+<target>Επιλογή μεθόδου</target>
<source>
Files are found equal if
@@ -607,7 +592,7 @@ is the same
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target><- Διπλής κατεύθυνσης -></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
<target>Αναγνώριση και αναπαραγωγή των αλλαγών και στις δύο πλευρές με τη χρήση μιας βάσης δεδομένων. Διαγραφές, μετονομασίες και διενέξεις ανιχνεύονται αυτόματα.</target>
@@ -643,7 +628,7 @@ is the same
<target>Κάδος Ανακύκλωσης</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Χρήση του Κάδου Ανακύκλωσης για αρχεία που διαγράφηκαν ή αντικαταστάθηκαν</target>
<source>Versioning</source>
<target>Διατήρηση παλιών εκδόσεων</target>
@@ -652,7 +637,7 @@ is the same
<target>Μεταφορά χρονοσημασμένων αρχείων σε συγκεκριμένο υποκατάλογο</target>
<source>Naming convention:</source>
-<target></target>
+<target>Τρόπος ονομασίας:</target>
<source>Configuration</source>
<target>Διάταξη</target>
@@ -681,7 +666,7 @@ is the same
<source>&Pause</source>
<target>&Παύση</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Ο πηγαίος κώδικας γράφτηκε σε C++ χρησιμοποιώντας τα:</target>
<source>If you like FreeFileSync</source>
@@ -771,6 +756,9 @@ Note: File names must be relative to base directories!
<source>Description</source>
<target>Περιγραφή</target>
+<source>Start synchronization</source>
+<target>Έναρξη του συγχρονισμού</target>
+
<source>Variant</source>
<target>Μέθοδος</target>
@@ -807,6 +795,15 @@ Note: File names must be relative to base directories!
<source>Select view</source>
<target>Επιλογή εμφάνισης</target>
+<source>Open...</source>
+<target></target>
+
+<source>Save</source>
+<target>Αποθήκευση</target>
+
+<source>Compare both sides</source>
+<target>Σύγκριση των δύο πλευρών</target>
+
<source>Set direction:</source>
<target>Επιλογή κατεύθυνσης:</target>
@@ -960,6 +957,9 @@ Note: File names must be relative to base directories!
<source>Show files that won't be copied</source>
<target>Εμφάνιση των αρχείων που δε θα αντιγραφούν</target>
+<source>Set as default</source>
+<target></target>
+
<source>All folders are in sync!</source>
<target>Όλοι οι υποκατάλογοι είναι συγχρονισμένοι!</target>
@@ -973,15 +973,6 @@ Note: File names must be relative to base directories!
<target>Ο κατάλογος των αρχείων έχει εξαχθεί!</target>
<source>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</source>
-<target>
-<pluralform>Το αντικείμενο διαγράφηκε επιτυχώς!</pluralform>
-<pluralform>%x αντικείμενα διαγράφηκαν επιτυχώς!</pluralform>
-</target>
-
-<source>
<pluralform>1 directory</pluralform>
<pluralform>%x directories</pluralform>
</source>
@@ -1033,7 +1024,7 @@ Note: File names must be relative to base directories!
<target>Σύγκριση του περιεχομένου...</target>
<source>Copy</source>
-<target></target>
+<target>Αντιγραφή</target>
<source>Paused</source>
<target>Σε παύση</target>
@@ -1048,13 +1039,13 @@ Note: File names must be relative to base directories!
<target>Ολοκληρώθηκε</target>
<source>Continue</source>
-<target>Συνέχεια</target>
+<target>Συνέχιση</target>
<source>Pause</source>
<target>Παύση</target>
<source>Logging</source>
-<target>Καταγραφή μηνυμάτων</target>
+<target>Καταγραφέντα μηνύματα</target>
<source>Cannot find %x</source>
<target>Δεν μπορεί να βρεθεί το %x</target>
@@ -1102,19 +1093,19 @@ Note: File names must be relative to base directories!
<target>Ένταξη εξωτερικών εφαρμογών στο μενού περιβάλλοντος. Οι ακόλουθες μακροεντολές είναι διαθέσιμες:</target>
<source>- full file or folder name</source>
-<target>- πλήρε όνομα αρχείου ή υποκαταλόγου</target>
+<target>- πλήρες όνομα αρχείου ή υποκαταλόγου</target>
<source>- folder part only</source>
<target>- μέρος μόνο του υποκαταλόγου</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- Το αντίστοιχο του %item_path% της άλλης πλευράς</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- Το αντίστοιχο του %item_folder% της άλλης πλευράς</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Να επανεμφανιστούν τα κρυμμένα μηνύματα και προειδοποιήσεις;</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1137,23 +1128,23 @@ Note: File names must be relative to base directories!
<source>Leave as unresolved conflict</source>
<target>Παράβλεψη ως ανεπίλυτη διένεξη</target>
+<source>Append a timestamp to each file name</source>
+<target>Προσάρτηση χρονικής σήμανσης σε κάθε όνομα αρχείου</target>
+
<source>Replace</source>
-<target></target>
+<target>Αντικατάσταση προηγούμενης</target>
<source>Move files and replace if existing</source>
-<target></target>
-
-<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Μετακίνηση αρχείων και αντικατάσταση</target>
<source>Folder</source>
-<target></target>
+<target>Υποκατάλογος</target>
<source>File</source>
-<target></target>
+<target>Αρχείο</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>ΕΕΕΕ-ΜΜ-ΗΗ ωωλλδδ</target>
<source>Files</source>
<target>Αρχεία</target>
@@ -1210,7 +1201,7 @@ Note: File names must be relative to base directories!
<target>Δεν μπορεί να αντιγραφεί το αρχείο %x στο %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>Ο τύπος του στοιχείου %x δεν υποστηρίζεται:</target>
<source>Cannot open directory %x.</source>
<target>Δεν είναι δυνατό το άνοιγμα του υποκαταλόγου %x.</target>
@@ -1278,6 +1269,27 @@ Note: File names must be relative to base directories!
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Ρύθμιση προεπιλεγμένης κατεύθυνσης συγχρονισμού: Τα νεότερα αρχεία θα αντικαταστήσουν τα παλιότερα.</target>
+<source>Checking recycle bin availability for folder %x...</source>
+<target></target>
+
+<source>Moving file %x to recycle bin</source>
+<target>Μεταφορά του αρχείου %x στον κάδο ανακύκλωσης</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>Μεταφορά του υποκαταλόγου %x στον κάδο ανακύκλωσης</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>Μεταφορά του συμβολικού δεσμού %x στον κάδο ανακύκλωσης</target>
+
+<source>Deleting file %x</source>
+<target>Διαγραφή του αρχείου %x</target>
+
+<source>Deleting folder %x</source>
+<target>Διαγραφή του υποκαταλόγου %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Διαγραφή του συμβολικού δεσμού %x</target>
+
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Ο Κάδος Ανακύκλωσης δεν είναι διαθέσιμος για τις ακόλουθες διαδρομές! Τα αρχεία θα διαγραφούν μόνιμα:</target>
@@ -1359,24 +1371,6 @@ Note: File names must be relative to base directories!
<source>Multiple...</source>
<target>Πολλαπλές ρυθμίσεις...</target>
-<source>Deleting file %x</source>
-<target>Διαγραφή του αρχείου %x</target>
-
-<source>Deleting folder %x</source>
-<target>Διαγραφή του υποκαταλόγου %x</target>
-
-<source>Deleting symbolic link %x</source>
-<target>Διαγραφή του συμβολικού δεσμού %x</target>
-
-<source>Moving file %x to recycle bin</source>
-<target>Μεταφορά του αρχείου %x στον κάδο ανακύκλωσης</target>
-
-<source>Moving folder %x to recycle bin</source>
-<target>Μεταφορά του υποκαταλόγου %x στον κάδο ανακύκλωσης</target>
-
-<source>Moving symbolic link %x to recycle bin</source>
-<target>Μεταφορά του συμβολικού δεσμού %x στον κάδο ανακύκλωσης</target>
-
<source>Moving file %x to %y</source>
<target>Μεταφορά του αρχείου %x στο %y</target>
@@ -1387,7 +1381,7 @@ Note: File names must be relative to base directories!
<target>Μεταφορά του συμβολικού δεσμού %x στο %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Διαγραφή παλιών εκδόσεων...</target>
<source>Creating file %x</source>
<target>Δημιουργία του αρχείου %x</target>
@@ -1423,7 +1417,7 @@ Note: File names must be relative to base directories!
<target>Ο υποκατάλογος %x δε βρέθηκε.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>Τα ακόλουθα στοιχεία έχουν ανεπίλυτες διενέξεις και δε θα συγχρονιστούν:</target>
<source>Significant difference detected:</source>
<target>Ανιχνεύθηκαν σημαντικές διαφορές:</target>
diff --git a/BUILD/Languages/hebrew.lng b/BUILD/Languages/hebrew.lng
index 532a3bcc..a7182126 100644
--- a/BUILD/Languages/hebrew.lng
+++ b/BUILD/Languages/hebrew.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>התקבלה בקשת ביטול: מחכה לפעולה הנוכחית להסתיים...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>נכשל ייצור תג זמן עבור עדכון גרסאות</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ is the same
<source>&Pause</source>
<target>&עצור</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>קוד מקור נכתב ב- C++ באמצעות:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/hungarian.lng b/BUILD/Languages/hungarian.lng
index e0ced192..385eaec3 100644
--- a/BUILD/Languages/hungarian.lng
+++ b/BUILD/Languages/hungarian.lng
@@ -31,8 +31,8 @@
<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>Failure to create time stamp for versioning:</source>
-<target></target>
+<source>Failure to create timestamp for versioning:</source>
+<target>A verziókövetéshez szükséges időbélyeg létrehozása sikertelen:</target>
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Automatikus szinkronizálás</target>
@@ -59,7 +59,7 @@
<target>Szűrőbeállítások törlése</target>
<source>Save as batch job</source>
-<target></target>
+<target>Mentés kötegelt feladatként</target>
<source>Comparison settings</source>
<target>Összehasonlítási beállítások</target>
@@ -272,7 +272,7 @@
<target>Mappa kiválasztása</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Tétlenségi idő (másodpercekben)</target>
<source>Idle time between last detected change and execution of command</source>
<target>Tétlenség időtartama az utolsó változás észlelése és a parancs végrehajtása között</target>
@@ -328,16 +328,16 @@ A parancs végrehajtódik, ha:
<target>A szinkronizáció befejeződött, de akadtak hibák!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>A szinkronizáció befejeződött figyelmeztetésekkel.</target>
<source>Nothing to synchronize!</source>
<target>Nincs mit szinkronizálni!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>A szinkronizáció sikeresen befejeződött.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Naplófájl mentése a következő fájlba: %x.</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>
@@ -361,7 +361,7 @@ A parancs végrehajtódik, ha:
<target>A csatlakozás a sourceforge.net-hez sikertelen!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>A jelenlegi FreeFileSync verziószám nem található meg online. Akarod manuálisan ellenőrizni?</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Akarod, hogy a FreeFileSync automatikusan minden héten keressen frissítést?</target>
@@ -433,7 +433,7 @@ A parancs végrehajtódik, ha:
<target>&Mentés</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Mentés &kötegelt feladatként...</target>
<source>1. &Compare</source>
<target>1. &Összehasonlítás</target>
@@ -481,16 +481,16 @@ A parancs végrehajtódik, ha:
<target>Oldalak felcserélése</target>
<source>Open</source>
-<target></target>
+<target>Megnyitás</target>
<source>Save</source>
-<target></target>
+<target>Mentés</target>
<source>Last used configurations (press DEL to remove from list)</source>
<target>Utoljára használt beállítások (DEL billentyűvel törölhető a listából)</target>
<source>Hide excluded items</source>
-<target></target>
+<target>Kizárt elemek elrejtése</target>
<source>Show filtered or temporarily excluded files</source>
<target>A szűrt vagy ideiglenesen kizárt fájlok mutatása</target>
@@ -550,13 +550,13 @@ A parancs végrehajtódik, ha:
<target>Szinkronizáció leállítása az első hibánál</target>
<source>On completion</source>
-<target></target>
+<target>Befejezés esetén</target>
<source>Show progress dialog</source>
<target>Folyamatjelző párbeszédablak mutatása</target>
<source>Save log</source>
-<target></target>
+<target>Naplófájl mentése</target>
<source>Select folder to save log files</source>
<target>Válaszd ki a mappát a naplófájlok mentéséhez</target>
@@ -568,7 +568,7 @@ A parancs végrehajtódik, ha:
<target>Naplófájlok maximális számának korlátozása</target>
<source>Select variant</source>
-<target></target>
+<target>Változat kiválasztása</target>
<source>
Files are found equal if
@@ -605,7 +605,7 @@ A fájlok megegyeznek, ha megegyezik
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target><- Kétirányú -></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
<target>Változások azonosítása és végrehajtása mindkét oldalon adatbázis segítségével. Automatikusan felismerődnek a törlések, átnevezések és ütközések.</target>
@@ -641,7 +641,7 @@ A fájlok megegyeznek, ha megegyezik
<target>Lomtár (Recycle Bin)</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Lomtár használata a törölt és felülírt fájlokhoz</target>
<source>Versioning</source>
<target>Verziókövetés</target>
@@ -650,7 +650,7 @@ A fájlok megegyeznek, ha megegyezik
<target>Időbélyeges fájlok mozgatása a megadott mappába</target>
<source>Naming convention:</source>
-<target></target>
+<target>Elnevezési konvenció:</target>
<source>Configuration</source>
<target>Beállítás</target>
@@ -679,7 +679,7 @@ A fájlok megegyeznek, ha megegyezik
<source>&Pause</source>
<target>&Szünet</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>A programot C++-ban fejlesztették a következők felhasználásával:</target>
<source>If you like FreeFileSync</source>
@@ -958,6 +958,9 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Show files that won't be copied</source>
<target>A nem másolandó fájlok mutatása</target>
+<source>Set as default</source>
+<target></target>
+
<source>All folders are in sync!</source>
<target>Minden mappa szinkronban!</target>
@@ -971,15 +974,6 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>A fájllista exportálása befejeződött!</target>
<source>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</source>
-<target>
-<pluralform>Sikeresen töröltük az objektumot!</pluralform>
-<pluralform>Sikeresen töröltünk %x objektumot!</pluralform>
-</target>
-
-<source>
<pluralform>1 directory</pluralform>
<pluralform>%x directories</pluralform>
</source>
@@ -1031,7 +1025,7 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>Tartalom összehasonlítása...</target>
<source>Copy</source>
-<target></target>
+<target>Másolás</target>
<source>Paused</source>
<target>Szüneteltetve</target>
@@ -1106,13 +1100,13 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>- csak mappa rész</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- A másik oldal megfelelőjét a következő fájlba: %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- A másik oldal megfelelőjét a következő mappába: %item_path%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Tegyük újra láthatóvá a rejtett figyelmeztetéseket és párbeszédablakokat?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1135,23 +1129,23 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Leave as unresolved conflict</source>
<target>Feloldatlan ütközésként hagyni</target>
+<source>Append a timestamp to each file name</source>
+<target>Időbélyeg hozzáadása a minden fájlnévhez</target>
+
<source>Replace</source>
-<target></target>
+<target>Felülírás</target>
<source>Move files and replace if existing</source>
-<target></target>
-
-<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Fájlok mozgatása és felülírása létezés esetén</target>
<source>Folder</source>
-<target></target>
+<target>Mappa</target>
<source>File</source>
-<target></target>
+<target>Fájl</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>ÉÉÉÉ-HH-NN óóppmm</target>
<source>Files</source>
<target>Fájlok</target>
@@ -1208,7 +1202,7 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>%x fájl másolása a(z) %y fájlba sikertelen.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>A(z) %x elem típusa nem támogatott:</target>
<source>Cannot open directory %x.</source>
<target>A következő mappa megnyitása sikertelen: %x.</target>
@@ -1276,6 +1270,27 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Alapértelmezett szinkronizációs irányok beállítása: a régebbi fájlok felülíródnak az újabbakkal.</target>
+<source>Checking recycle bin availability for folder %x...</source>
+<target></target>
+
+<source>Moving file %x to recycle bin</source>
+<target>%x fájl mozgatása a Lomtárba (Recycle Bin)</target>
+
+<source>Moving folder %x to recycle bin</source>
+<target>%x mappa mozgatása a Lomtárba (Recycle Bin)</target>
+
+<source>Moving symbolic link %x to recycle bin</source>
+<target>%x symlink mozgatása a Lomtárba (Recycle Bin)</target>
+
+<source>Deleting file %x</source>
+<target>Fájl törlése %x</target>
+
+<source>Deleting folder %x</source>
+<target>Mappa törlése %x</target>
+
+<source>Deleting symbolic link %x</source>
+<target>Symlink törlése: %x</target>
+
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>A Lomtár (Recycle Bin) nem elérhető a következő útvonalakhoz! A fájlok azonnali törlésre kerülnek helyette:</target>
@@ -1357,24 +1372,6 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Multiple...</source>
<target>Sokszorosítás</target>
-<source>Deleting file %x</source>
-<target>Fájl törlése %x</target>
-
-<source>Deleting folder %x</source>
-<target>Mappa törlése %x</target>
-
-<source>Deleting symbolic link %x</source>
-<target>Symlink törlése: %x</target>
-
-<source>Moving file %x to recycle bin</source>
-<target>%x fájl mozgatása a Lomtárba (Recycle Bin)</target>
-
-<source>Moving folder %x to recycle bin</source>
-<target>%x mappa mozgatása a Lomtárba (Recycle Bin)</target>
-
-<source>Moving symbolic link %x to recycle bin</source>
-<target>%x symlink mozgatása a Lomtárba (Recycle Bin)</target>
-
<source>Moving file %x to %y</source>
<target>%x fájl mozgatása ide: %y</target>
@@ -1385,7 +1382,7 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>%x symlink mozgatása ide: %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Régi verziók eltávolítása...</target>
<source>Creating file %x</source>
<target>%x fájl létrehozása</target>
@@ -1421,7 +1418,7 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<target>A következő forrásmappa nem található: %x.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>A következő elemek feloldatlan ütközésekkel rendelkeznek és nem lesznek szinkronizálva:</target>
<source>Significant difference detected:</source>
<target>Jelentős különbség érzékelve:</target>
diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng
index aff424ad..14eeaf79 100644
--- a/BUILD/Languages/italian.lng
+++ b/BUILD/Languages/italian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Selezionata interruazione: conclusione dell'operazione...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Errore nella creazione di data e ora per il controllo delle versioni:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ I file sono considerati identici se
<source>&Pause</source>
<target>&Pausa</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Codice sorgente scritto in C++ utilizzando:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng
index f5e7eb49..25935c29 100644
--- a/BUILD/Languages/japanese.lng
+++ b/BUILD/Languages/japanese.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>ユーザによる中断: 現在の処理を終了しています.. お待ちください...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>バージョン付けのタイムスタンプ作成に失敗:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -678,7 +678,7 @@ is the same
<source>&Pause</source>
<target>一時停止(&P)</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>ソースコードは C++ で書かれています</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/korean.lng b/BUILD/Languages/korean.lng
index 501e38e6..b4b28480 100644
--- a/BUILD/Languages/korean.lng
+++ b/BUILD/Languages/korean.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>사용자에 의한 작업 중단 : 현재 작업 종료 대기 중...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>버저닝을 위한 타임 스탬프 생성 실패 :</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -678,7 +678,7 @@ is the same
<source>&Pause</source>
<target>일시정지(&P)</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>소스코드는 C++ 언어로 아래 툴을 사용하여 작성되었습니다 :</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/lithuanian.lng b/BUILD/Languages/lithuanian.lng
index 9180212b..4c0b74ec 100644
--- a/BUILD/Languages/lithuanian.lng
+++ b/BUILD/Languages/lithuanian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Nutraukti: laukiama kol baigsis esama operacija...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Nepavyo sukurti laiko žymės versijavimui:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -687,7 +687,7 @@ yra toks pats
<source>&Pause</source>
<target>&Pauzė</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Šaltinio kodas parašytas su C++ naudojant:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/norwegian.lng b/BUILD/Languages/norwegian.lng
index 8850a52b..91672bab 100644
--- a/BUILD/Languages/norwegian.lng
+++ b/BUILD/Languages/norwegian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Avbrytelse forespurt: Venter på at gjeldende handling avsluttes...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target></target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -59,7 +59,7 @@
<target>Nullstill filterinnstillinger</target>
<source>Save as batch job</source>
-<target></target>
+<target>Lagre som sammensatt oppgave</target>
<source>Comparison settings</source>
<target>Innstillinger for sammenligning</target>
@@ -224,7 +224,7 @@
<target>&Åpne</target>
<source>Save &as...</source>
-<target></target>
+<target>Lagre &som</target>
<source>&Quit</source>
<target>&Avslutt</target>
@@ -272,7 +272,7 @@
<target>Velg en mappe</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Ventetid [sekunder]</target>
<source>Idle time between last detected change and execution of command</source>
<target>Ventetid mellom forrige endring og utførelse av kommando</target>
@@ -328,16 +328,16 @@ Kommandoen utløses hvis:
<target>Synkronisering fullført med feil!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>Synkronisering fullført med advarsler.</target>
<source>Nothing to synchronize!</source>
<target>Ikke noe å synkronisere!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>Synkdonisering fullført.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Lagrer loggfil %x...</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
<target>Trykk "Skift" for å løse problemer i FreeFileSync hovedvindu.</target>
@@ -361,7 +361,7 @@ Kommandoen utløses hvis:
<target>Ikke i stand til å koble til sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>Nyeste FreeFileSyncversjon ble ikke funnet online! Vil du sjekke manuelt?</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Skal FreeFileSync automatisk se etter oppdateringer hver uke?</target>
@@ -433,7 +433,7 @@ Kommandoen utløses hvis:
<target>&Lagre</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Lagre som &sammensatt jobb...</target>
<source>1. &Compare</source>
<target>1. Sammen&lign</target>
@@ -459,18 +459,12 @@ Kommandoen utløses hvis:
<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>
@@ -480,20 +474,11 @@ Kommandoen utløses hvis:
<source>Swap sides</source>
<target>Bytt sider</target>
-<source>Open</source>
-<target></target>
-
-<source>Save</source>
-<target></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></target>
+<target>Gjem ekskluderte elementer</target>
<source>Show filtered or temporarily excluded files</source>
-<target></target>
+<target>Vis filtrerte eller midlertidig ekskluderte filer</target>
<source>Number of files and folders that will be created</source>
<target>Antall filer og mapper som vil opprettes</target>
@@ -532,43 +517,43 @@ Kommandoen utløses hvis:
<target>Feilhåndtering</target>
<source>Ignore</source>
-<target></target>
+<target>Ignorer</target>
<source>Hide all error and warning messages</source>
<target>Skjul feilmeldinger og advarsler</target>
<source>Pop-up</source>
-<target></target>
+<target>Pop-up</target>
<source>Show pop-up on errors or warnings</source>
<target>Vis pop-upvindu ved feil eller advarsler</target>
<source>Exit</source>
-<target></target>
+<target>Avslutt</target>
<source>Abort synchronization on first error</source>
-<target></target>
+<target>Stopp synkronisering ved første feil</target>
<source>On completion</source>
-<target></target>
+<target>Ved fullføring</target>
<source>Show progress dialog</source>
<target>Vis dialogboks</target>
<source>Save log</source>
-<target></target>
+<target>Lagre logg</target>
<source>Select folder to save log files</source>
-<target></target>
+<target>Velg mappe du vil lagre loggfiler i</target>
<source>Limit</source>
-<target></target>
+<target>Grense</target>
<source>Limit maximum number of log files</source>
-<target></target>
+<target>Begrens maks antall loggfiler</target>
<source>Select variant</source>
-<target></target>
+<target>Velg variant</target>
<source>
Files are found equal if
@@ -607,7 +592,7 @@ er det samme
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target><- Toveis -></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>
@@ -634,25 +619,25 @@ er det samme
<target>Slette-håndtering</target>
<source>Permanent</source>
-<target></target>
+<target>Permanent</target>
<source>Delete or overwrite files permanently</source>
<target>Slett eller overskriv filer permanent</target>
<source>Recycle Bin</source>
-<target></target>
+<target>Papirkurv</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Bruk papirkurv for slettede og overskrevne filer</target>
<source>Versioning</source>
<target>Versjonshåndtering</target>
<source>Move time-stamped files into specified folder</source>
-<target></target>
+<target>Flytt tidsstemplede filer den valgte mappen</target>
<source>Naming convention:</source>
-<target></target>
+<target>Navnekonvensjon:</target>
<source>Configuration</source>
<target>Innstilling</target>
@@ -681,7 +666,7 @@ er det samme
<source>&Pause</source>
<target>&Pause</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Kildekode skrevet i C++ med hjelp fra:</target>
<source>If you like FreeFileSync</source>
@@ -691,7 +676,7 @@ er det samme
<target>Doner med PayPal</target>
<source>Many thanks for localization:</source>
-<target></target>
+<target>Mange takk for lokalisering:</target>
<source>Feedback and suggestions are welcome</source>
<target>Tilbakemelding og forslag er velkomne</target>
@@ -771,6 +756,9 @@ Merk: Filnavn må være relative til basismapper!
<source>Description</source>
<target>Beskrivelse</target>
+<source>Start synchronization</source>
+<target>Start synkronisering</target>
+
<source>Variant</source>
<target>Variant</target>
@@ -778,7 +766,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Statistikk</target>
<source>Don't show this dialog again</source>
-<target></target>
+<target>Ikke vis dette vinduet igjen</target>
<source>Find what:</source>
<target>Søk hva:</target>
@@ -807,6 +795,15 @@ Merk: Filnavn må være relative til basismapper!
<source>Select view</source>
<target>Velg visning</target>
+<source>Open...</source>
+<target></target>
+
+<source>Save</source>
+<target>Lagre</target>
+
+<source>Compare both sides</source>
+<target>Sammenlign begge sider</target>
+
<source>Set direction:</source>
<target>Still inn retningen:</target>
@@ -871,7 +868,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Vil du lagre endringene til %x?</target>
<source>Do&n't save</source>
-<target></target>
+<target>&Ikke lagre</target>
<source>Configuration loaded!</source>
<target>Innstilling lastet!</target>
@@ -960,9 +957,12 @@ Merk: Filnavn må være relative til basismapper!
<source>Show files that won't be copied</source>
<target>Vis filer som ikke blir kopiert</target>
-<source>All folders are in sync!</source>
+<source>Set as default</source>
<target></target>
+<source>All folders are in sync!</source>
+<target>Alle mapper er synkroniserte!</target>
+
<source>Comma separated list</source>
<target>Komma-separert liste</target>
@@ -973,15 +973,6 @@ Merk: Filnavn må være relative til basismapper!
<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>
@@ -1033,7 +1024,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Sammenligner innhold...</target>
<source>Copy</source>
-<target></target>
+<target>Kopier</target>
<source>Paused</source>
<target>Pauset</target>
@@ -1108,13 +1099,13 @@ Merk: Filnavn må være relative til basismapper!
<target>- kun mapper</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- Den andre sidens motpart til %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- Den andre sidens motpart til %item_folder%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Gjør skjylte advarsler og dialoger synlige igjen?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1137,23 +1128,23 @@ Merk: Filnavn må være relative til basismapper!
<source>Leave as unresolved conflict</source>
<target>Etterlat som uløste konflikter</target>
+<source>Append a timestamp to each file name</source>
+<target>Legg til et tidsstempel til hvert filnavn</target>
+
<source>Replace</source>
-<target></target>
+<target>Erstatt</target>
<source>Move files and replace if existing</source>
-<target></target>
-
-<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Flytt filer og erstatt hvis eksisterer</target>
<source>Folder</source>
-<target></target>
+<target>Mappe</target>
<source>File</source>
-<target></target>
+<target>Fil</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>ÅÅÅÅ-MM-DD ttmmss</target>
<source>Files</source>
<target>Filer</target>
@@ -1210,13 +1201,13 @@ Merk: Filnavn må være relative til basismapper!
<target>Kan ikke kopiere filen %x til %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>Type element %x er ikke støttet:</target>
<source>Cannot open directory %x.</source>
-<target></target>
+<target>Kan ikke åpne mappe %x.</target>
<source>Cannot enumerate directory %x.</source>
-<target></target>
+<target>Kan ikke gjennomgå mappe %x.</target>
<source>Detected endless directory recursion.</source>
<target>Fant uendelig dyp mappestruktur (lenker til mapper høyere opp i strukturen)</target>
@@ -1278,6 +1269,27 @@ Merk: Filnavn må være relative til basismapper!
<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>Checking recycle bin availability for folder %x...</source>
+<target></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>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>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>
@@ -1291,7 +1303,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Mapper er avhengige av hverandre! Vær forsiktig når du setter opp synkroniseringsregler:</target>
<source>Start comparison</source>
-<target></target>
+<target>Start sammenligning</target>
<source>Preparing synchronization...</source>
<target>Forbereder synkronisering...</target>
@@ -1306,7 +1318,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Filer %x har den samme datoen, men forskjellig størrelse!</target>
<source>Items differ in attributes only</source>
-<target></target>
+<target>Elementer har kun forskjellige attributter</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>
@@ -1359,24 +1371,6 @@ Merk: Filnavn må være relative til basismapper!
<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>
@@ -1387,7 +1381,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Flytter symbolsk lenke %x til %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Fjerner gamle versjoner...</target>
<source>Creating file %x</source>
<target>Oppretter fil %x</target>
@@ -1423,7 +1417,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Kildemappe %x finnes ikke.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>De følgende elementene har uoppklarte konflikter og vil ikke bli synkroniserte:</target>
<source>Significant difference detected:</source>
<target>Betydelig forskjell oppdaget:</target>
@@ -1450,7 +1444,7 @@ Merk: Filnavn må være relative til basismapper!
<target>Høyre</target>
<source>Synchronizing folder pair:</source>
-<target></target>
+<target>Synkroniserer mappepar:</target>
<source>Generating database...</source>
<target>Oppretter database...</target>
diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng
index cebe529b..564db6dc 100644
--- a/BUILD/Languages/polish.lng
+++ b/BUILD/Languages/polish.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Żądanie przerwania: Oczekiwanie na koniec aktualnie wykonywanego zadania...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Nie można utworzyć sygnatury czasu na potrzeby wersjonowania:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -684,7 +684,7 @@ jest identyczna
<source>&Pause</source>
<target>&Pauza</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Kod stworzony w C++ z wykorzystaniem:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng
index dfc29c43..a187ff07 100644
--- a/BUILD/Languages/portuguese.lng
+++ b/BUILD/Languages/portuguese.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Abortar pedido: À espera do fim da operação atual...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Falha ao criar selo temporal para versões anteriores:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -680,7 +680,7 @@ Os ficheiros são considerados iguais se
<source>&Pause</source>
<target>&Pausa</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Código fonte escrito em C++ utilizando:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng
index 3182c088..0d4c2246 100644
--- a/BUILD/Languages/portuguese_br.lng
+++ b/BUILD/Languages/portuguese_br.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Cancelar solicitado: Esperando fim da operação...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Erro ao criar estampa de tempo para controle de versão:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ Os arquivos são considerados iguais se
<source>&Pause</source>
<target>&Pausar</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Código-fonte escrito em C++ utilizando:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng
index c99a2d55..a0370f4d 100644
--- a/BUILD/Languages/romanian.lng
+++ b/BUILD/Languages/romanian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Abandonare solicitată: Se așteaptă terminarea operației în curs...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Crearea marcajului temporal pentru versionare a eșuat</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -684,7 +684,7 @@ este același
<source>&Pause</source>
<target>&Pauzează</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Cod sursă scris în C++ folosind:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng
index 0ffed7e4..597f548c 100644
--- a/BUILD/Languages/russian.lng
+++ b/BUILD/Languages/russian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Запрос отмены: Ожидайте, пока текущая операция завершится...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Неспособность создать отметку времени для архивации файлов:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -682,7 +682,7 @@ is the same
<source>&Pause</source>
<target>&Пауза</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Исходный код написан на C++ с использованием:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/scottish_gaelic.lng b/BUILD/Languages/scottish_gaelic.lng
index 3e49bc3b..b3d635a6 100644
--- a/BUILD/Languages/scottish_gaelic.lng
+++ b/BUILD/Languages/scottish_gaelic.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Tha thu airson sgur dheth: A' feitheamh gus an crìochnaich an gnìomh làithreach...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Cha b' urrainn dhuinn stampa-ama a chruthachadh airson versioning:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -686,7 +686,7 @@ Bidh dà fhaidhle co-ionnann 'nar beachd-sa
<source>&Pause</source>
<target>&Cuir 'na stad</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Chaidh an còd tùsail a sgrìobhadh ann an C++ le taic:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng
index 3abe7273..4a916632 100644
--- a/BUILD/Languages/slovenian.lng
+++ b/BUILD/Languages/slovenian.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Zahtevana je bila prekinitev: čakam, da se zaključi trenutna operacija...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Napaka pri ustvarjanju časovne oznake pri ustvarjanju različic:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -687,7 +687,7 @@ enaka
<source>&Pause</source>
<target>&Premor</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Izvorna koda napisana v C++ z uporabo:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng
index 7de02d01..ed0286a0 100644
--- a/BUILD/Languages/spanish.lng
+++ b/BUILD/Languages/spanish.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Solicitud de aborto: Esperando a que la operación actual finalice...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Fallo al crear fecha y hora para el versionado:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ es el mismo
<source>&Pause</source>
<target>&Pausa</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Código fuente escrito en C++ utilizando:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng
index 64a62e20..9a727bfd 100644
--- a/BUILD/Languages/swedish.lng
+++ b/BUILD/Languages/swedish.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Avbryter: Väntar på att aktuell process skall slutföras...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Kunde inte skapa tidsstämpel för versionshantering</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ Filerna betecknas som lika om,
<source>&Pause</source>
<target>&Paus</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Källkod skriven i C++ med hjälp av:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng
index fdbd10b0..570156c8 100644
--- a/BUILD/Languages/turkish.lng
+++ b/BUILD/Languages/turkish.lng
@@ -31,7 +31,7 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Vazgeçildi: Yürürlükteki işlemin bitmesi bekleniyor...</target>
-<source>Failure to create time stamp for versioning:</source>
+<source>Failure to create timestamp for versioning:</source>
<target>Eski sürüm için zaman damgası oluşturulamadı:</target>
<source>RealtimeSync - Automated Synchronization</source>
@@ -681,7 +681,7 @@ aynı olmalıdır
<source>&Pause</source>
<target>&Duraklat</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Kaynak kodu C++ kullanılarak yazılmıştır:</target>
<source>If you like FreeFileSync</source>
diff --git a/BUILD/Languages/ukrainian.lng b/BUILD/Languages/ukrainian.lng
index 7c184097..a2a0923c 100644
--- a/BUILD/Languages/ukrainian.lng
+++ b/BUILD/Languages/ukrainian.lng
@@ -31,8 +31,8 @@
<source>Abort requested: Waiting for current operation to finish...</source>
<target>Запит переривання: В очікуванні завершення поточної операції...</target>
-<source>Failure to create time stamp for versioning:</source>
-<target></target>
+<source>Failure to create timestamp for versioning:</source>
+<target>Не вдається створити часової мітки для версій:</target>
<source>RealtimeSync - Automated Synchronization</source>
<target>RealtimeSync - Автоматична синхронізація</target>
@@ -59,7 +59,7 @@
<target>Очистити налаштування фільтра</target>
<source>Save as batch job</source>
-<target></target>
+<target>Зберегти як пакетне завдання</target>
<source>Comparison settings</source>
<target>Налаштування порівнювання</target>
@@ -275,7 +275,7 @@
<target>Вибрати папку</target>
<source>Idle time [seconds]</source>
-<target></target>
+<target>Час простою [секунд]</target>
<source>Idle time between last detected change and execution of command</source>
<target>Час простою між виявленням останньої зміни та виконанням команди</target>
@@ -331,16 +331,16 @@ The command is triggered if:
<target>Синхронізація закінчилася з помилками!</target>
<source>Synchronization completed with warnings.</source>
-<target></target>
+<target>Синхронізація завершена з попередженнями.</target>
<source>Nothing to synchronize!</source>
<target>Нічого синхронізувати!</target>
<source>Synchronization completed successfully.</source>
-<target></target>
+<target>Синхронізація успішно завершена.</target>
<source>Saving log file %x...</source>
-<target></target>
+<target>Збереження файла журналу %x...</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
<target>Натисніть "Змінити" для вирішення питань у головному вікні FreeFileSync.</target>
@@ -364,7 +364,7 @@ The command is triggered if:
<target>Не можна з’єднатися з sourceforge.net!</target>
<source>Current FreeFileSync version number was not found online! Do you want to check manually?</source>
-<target></target>
+<target>Номер поточної версії FreeFileSync не знайдений онлайн! Хочете перевірити вручну?</target>
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Ви хочете, щоб FreeFileSync автоматично перевіряв наявність оновлень щотижня?</target>
@@ -436,7 +436,7 @@ The command is triggered if:
<target>Зберегти</target>
<source>Save as &batch job...</source>
-<target></target>
+<target>Зберегти як пакетне завдання</target>
<source>1. &Compare</source>
<target>1. &Порівняти</target>
@@ -484,10 +484,10 @@ The command is triggered if:
<target>Поміняти місцями</target>
<source>Open</source>
-<target></target>
+<target>Відкрити</target>
<source>Save</source>
-<target></target>
+<target>Зберегти</target>
<source>Last used configurations (press DEL to remove from list)</source>
<target>
@@ -496,7 +496,7 @@ The command is triggered if:
</target>
<source>Hide excluded items</source>
-<target></target>
+<target>Приховати виключені елементи</target>
<source>Show filtered or temporarily excluded files</source>
<target>Показати відфільтровані чи тимчасово виключені елементи</target>
@@ -556,13 +556,13 @@ The command is triggered if:
<target>Перервати синхронізацію при першій помилці</target>
<source>On completion</source>
-<target></target>
+<target>Після завершення</target>
<source>Show progress dialog</source>
<target>Показувати вікно прогресу</target>
<source>Save log</source>
-<target></target>
+<target>Зберегти журнал</target>
<source>Select folder to save log files</source>
<target>Виберіть папку для файлів журналу</target>
@@ -574,7 +574,7 @@ The command is triggered if:
<target>Обмежити максимальну кількість файлів журналу</target>
<source>Select variant</source>
-<target></target>
+<target>Виберіть варіант</target>
<source>
Files are found equal if
@@ -609,7 +609,7 @@ is the same
<target>OK</target>
<source><- Two way -></source>
-<target></target>
+<target><- Обидва напрямки -></target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
<target>Виявити та поширити зміни на обидві сторони використовуючи базу даних. Видалення, перейменування та конфлікти визначаються автоматично.</target>
@@ -645,7 +645,7 @@ is the same
<target>Корзина</target>
<source>Use Recycle Bin for deleted and overwritten files</source>
-<target></target>
+<target>Використати Корзину для видалених і перезаписаних файлів</target>
<source>Versioning</source>
<target>Запис версій</target>
@@ -654,7 +654,7 @@ is the same
<target>Перемістити файли з часовою міткою у вказану папку</target>
<source>Naming convention:</source>
-<target></target>
+<target>Метод іменування:</target>
<source>Configuration</source>
<target>Налаштування</target>
@@ -683,7 +683,7 @@ is the same
<source>&Pause</source>
<target>&Пауза</target>
-<source>Source code written in C++ utilizing:</source>
+<source>Source code written in C++ using:</source>
<target>Код програми написаний на C++ з використанням:</target>
<source>If you like FreeFileSync</source>
@@ -809,6 +809,12 @@ Note: File names must be relative to base directories!
<source>Select view</source>
<target>Список файлів</target>
+<source>Deleting file %x</source>
+<target>Вилучення файлу %x</target>
+
+<source>Deleting %x</source>
+<target></target>
+
<source>Set direction:</source>
<target>Виберіть напрям:</target>
@@ -962,6 +968,9 @@ Note: File names must be relative to base directories!
<source>Show files that won't be copied</source>
<target>Показати файли, які не будуть зкопійовані</target>
+<source>Set as default</source>
+<target></target>
+
<source>All folders are in sync!</source>
<target>Всі папки синхронізовано!</target>
@@ -975,16 +984,6 @@ Note: File names must be relative to base directories!
<target>Список файлів експортовано!</target>
<source>
-<pluralform>Object deleted successfully!</pluralform>
-<pluralform>%x objects deleted successfully!</pluralform>
-</source>
-<target>
-<pluralform>%x об'єкт успішно вилучено!</pluralform>
-<pluralform>%x об'єкти успішно вилучено!</pluralform>
-<pluralform>%x об'єктів успішно вилучено!</pluralform>
-</target>
-
-<source>
<pluralform>1 directory</pluralform>
<pluralform>%x directories</pluralform>
</source>
@@ -1039,7 +1038,7 @@ Note: File names must be relative to base directories!
<target>Порівнювання вмісту...</target>
<source>Copy</source>
-<target></target>
+<target>Копія</target>
<source>Paused</source>
<target>Призупинено</target>
@@ -1114,13 +1113,13 @@ Note: File names must be relative to base directories!
<target>- тільки папка</target>
<source>- Other side's counterpart to %item_path%</source>
-<target></target>
+<target>- Елемент з протилежної сторони до %item_path%</target>
<source>- Other side's counterpart to %item_folder%</source>
-<target></target>
+<target>- Елемент з протилежної сторони до %item_folder%</target>
<source>Make hidden warnings and dialogs visible again?</source>
-<target></target>
+<target>Зробити приховані попередження та діалоги ​​знову видимими?</target>
<source>
<pluralform>Do you really want to move the following object to the Recycle Bin?</pluralform>
@@ -1146,22 +1145,22 @@ Note: File names must be relative to base directories!
<target>Залишити як невирішений конфлікт</target>
<source>Replace</source>
-<target></target>
+<target>Замінити</target>
<source>Move files and replace if existing</source>
-<target></target>
+<target>Перемістити файли замінюючи існуючі</target>
<source>Append a timestamp to each file name</source>
-<target></target>
+<target>Додати часову мітку до кожного імені файлу</target>
<source>Folder</source>
-<target></target>
+<target>Папка</target>
<source>File</source>
-<target></target>
+<target>Файл</target>
<source>YYYY-MM-DD hhmmss</source>
-<target></target>
+<target>YYYY-MM-DD hhmmss</target>
<source>Files</source>
<target>Файли</target>
@@ -1218,7 +1217,7 @@ Note: File names must be relative to base directories!
<target>Не вдається зкопіювати файл %х до %y.</target>
<source>Type of item %x is not supported:</source>
-<target></target>
+<target>Тип елемента %х не підтримується:</target>
<source>Cannot open directory %x.</source>
<target>Не вдається відкрити каталогу %x.</target>
@@ -1292,6 +1291,9 @@ Note: File names must be relative to base directories!
Старі файли будуть замінені новішими файлами.
</target>
+<source>Checking recycle bin availability for folder %x...</source>
+<target></target>
+
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Корзина для цього шляху недоступна. Файли будуть вилучені назавжди:</target>
@@ -1373,9 +1375,6 @@ Note: File names must be relative to base directories!
<source>Multiple...</source>
<target>Різні варіанти...</target>
-<source>Deleting file %x</source>
-<target>Вилучення файлу %x</target>
-
<source>Deleting folder %x</source>
<target>Вилучення папки %x</target>
@@ -1401,7 +1400,7 @@ Note: File names must be relative to base directories!
<target>Переміщення символьного посилання %x до %y</target>
<source>Removing old versions...</source>
-<target></target>
+<target>Видалення старих версій...</target>
<source>Creating file %x</source>
<target>Створення файлу %x</target>
@@ -1437,7 +1436,7 @@ Note: File names must be relative to base directories!
<target>Вихідний каталог %x не знайдено.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target></target>
+<target>Наступні елементи мають невирішені конфлікти і не будуть синхронізовані:</target>
<source>Significant difference detected:</source>
<target>Виявлена істотна різниця:</target>
diff --git a/BUILD/Resources.zip b/BUILD/Resources.zip
index 3b646713..79efed0d 100644
--- a/BUILD/Resources.zip
+++ b/BUILD/Resources.zip
Binary files differ
diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp
deleted file mode 100644
index f2abfcc6..00000000
--- a/FreeFileSync.cbp
+++ /dev/null
@@ -1,538 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<CodeBlocks_project_file>
- <FileVersion major="1" minor="6" />
- <Project>
- <Option title="FreeFileSync" />
- <Option makefile="makefile" />
- <Option pch_mode="2" />
- <Option compiler="gcc" />
- <Build>
- <Target title="Release">
- <Option output="BUILD/Bin/FreeFileSync_Win32" prefix_auto="1" extension_auto="1" />
- <Option working_dir="BUILD/" />
- <Option object_output="OBJ/FFS_Release_32_MinGW/" />
- <Option type="0" />
- <Option compiler="gcc" />
- <Option projectCompilerOptionsRelation="2" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-O3" />
- <Add option="-DNDEBUG" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_release_lib/mswu" />
- </Compiler>
- <Linker>
- <Add option="-s" />
- <Add option="-static" />
- <Add library="libboost_thread-mgw47-mt-s-1_52.a" />
- <Add library="libboost_system-mgw47-mt-s-1_52.a" />
- <Add library="libwxmsw28u_aui.a" />
- <Add library="libwxmsw28u_adv.a" />
- <Add library="libwxmsw28u_core.a" />
- <Add library="libwxbase28u.a" />
- <Add library="libwxbase28u_net.a" />
- <Add library="libwxpng.a" />
- <Add library="libwxzlib.a" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_release_lib" />
- </Linker>
- <ExtraCommands>
- <Add after='&quot;C:\Program Files\C++\CodeSigning\SignCode.cmd&quot; &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot;' />
- </ExtraCommands>
- </Target>
- <Target title="Debug-DLL">
- <Option output="BUILD/Bin/FreeFileSync_Debug" prefix_auto="1" extension_auto="1" />
- <Option working_dir="BUILD" />
- <Option object_output="OBJ/FFS_Debug_32_MinGW/" />
- <Option type="0" />
- <Option compiler="gcc" />
- <Option projectCompilerOptionsRelation="2" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-g" />
- <Add option="-Winvalid-pch" />
- <Add option='-include &quot;wx+/pch.h&quot;' />
- <Add option="-D__WXDEBUG__" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_debug_dll/mswud" />
- </Compiler>
- <Linker>
- <Add library="libboost_thread-mgw47-mt-sd-1_52.a" />
- <Add library="libboost_system-mgw47-mt-sd-1_52.a" />
- <Add library="libwxmsw28ud_aui.a" />
- <Add library="libwxmsw28ud_adv.a" />
- <Add library="libwxmsw28ud_core.a" />
- <Add library="libwxbase28ud.a" />
- <Add library="libwxbase28ud_net.a" />
- <Add library="libwxzlibd.a" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_debug_dll" />
- </Linker>
- </Target>
- <Target title="Unit Test">
- <Option output="OBJ/Unit_Test_MinGW/Unit Test" prefix_auto="1" extension_auto="1" />
- <Option working_dir="OBJ/Unit_Test_MinGW/" />
- <Option object_output="OBJ/Unit_Test_MinGW/" />
- <Option type="1" />
- <Option compiler="gcc" />
- <Option projectCompilerOptionsRelation="2" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-g" />
- <Add option="-Winvalid-pch" />
- <Add option='-include &quot;wx+/pch.h&quot;' />
- <Add option="-D__WXDEBUG__" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_debug_dll/mswud" />
- <Add directory="lib/gtest" />
- <Add directory="lib/gtest/include" />
- </Compiler>
- <Linker>
- <Add library="libboost_thread-mgw47-mt-sd-1_52.a" />
- <Add library="libboost_system-mgw47-mt-sd-1_52.a" />
- <Add library="libwxmsw28ud_adv.a" />
- <Add library="libwxmsw28ud_core.a" />
- <Add library="libwxbase28ud.a" />
- <Add library="libwxpngd.a" />
- <Add library="libwxzlibd.a" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_debug_dll" />
- </Linker>
- </Target>
- </Build>
- <Compiler>
- <Add option="-Wshadow" />
- <Add option="-Winit-self" />
- <Add option="-Wredundant-decls" />
- <Add option="-Wcast-align" />
- <Add option="-Wunreachable-code" />
- <Add option="-Wmissing-include-dirs" />
- <Add option="-Wswitch-enum" />
- <Add option="-Wmain" />
- <Add option="-std=c++11" />
- <Add option="-Wall" />
- <Add option="-pipe" />
- <Add option="-mthreads" />
- <Add option="-fno-omit-frame-pointer" />
- <Add option='-include &quot;zen/warn_static.h&quot;' />
- <Add option="-std=gnu++0x" />
- <Add option="-D__GNUWIN32__" />
- <Add option="-D__WXMSW__" />
- <Add option="-DFFS_WIN" />
- <Add option="-DwxUSE_UNICODE" />
- <Add option="-DBOOST_THREAD_USE_LIB" />
- <Add option="-DWXINTL_NO_GETTEXT_MACRO" />
- <Add option="-DZEN_PLATFORM_WINDOWS" />
- <Add directory="C:/Programme/C++/wxWidgets/include" />
- <Add directory="C:/Program Files/C++/Boost" />
- <Add directory="." />
- </Compiler>
- <ResourceCompiler>
- <Add directory="C:/Programme/C++/wxWidgets/include" />
- </ResourceCompiler>
- <Linker>
- <Add option="-mthreads" />
- <Add library="libkernel32.a" />
- <Add library="libuser32.a" />
- <Add library="libuuid.a" />
- <Add library="libcomctl32.a" />
- <Add library="libole32.a" />
- <Add library="liboleaut32.a" />
- <Add library="libgdi32.a" />
- <Add library="libcomdlg32.a" />
- <Add library="libws2_32.a" />
- <Add library="libwinspool.a" />
- <Add library="libwinmm.a" />
- <Add library="libmpr.a" />
- <Add library="libuxtheme.a" />
- <Add library="libwininet.a" />
- <Add directory="C:/Program Files/C++/Boost/stage/lib" />
- </Linker>
- <Unit filename="WxWizFrame.fbp">
- <Option target="&lt;{~None~}&gt;" />
- </Unit>
- <Unit filename="algorithm.cpp" />
- <Unit filename="algorithm.h" />
- <Unit filename="application.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="application.h" />
- <Unit filename="comparison.cpp" />
- <Unit filename="comparison.h" />
- <Unit filename="file_hierarchy.cpp" />
- <Unit filename="file_hierarchy.h" />
- <Unit filename="lib/binary.cpp" />
- <Unit filename="lib/binary.h" />
- <Unit filename="lib/cmp_filetime.h" />
- <Unit filename="lib/db_file.cpp" />
- <Unit filename="lib/db_file.h" />
- <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/generate_logfile.h" />
- <Unit filename="lib/gtest/main.cpp">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/gtest/src/gtest-all.cc">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/gtest/unittest.h">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/gtest/unittest1.cpp">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/gtest/unittest2.cpp">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/gtest/unittest3.cpp">
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="lib/hard_filter.cpp" />
- <Unit filename="lib/hard_filter.h" />
- <Unit filename="lib/help_provider.h" />
- <Unit filename="lib/icon_buffer.cpp" />
- <Unit filename="lib/icon_buffer.h" />
- <Unit filename="lib/localization.cpp" />
- <Unit filename="lib/localization.h" />
- <Unit filename="lib/lock_holder.h" />
- <Unit filename="lib/norm_filter.h" />
- <Unit filename="lib/parallel_scan.cpp" />
- <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/resolve_path.cpp" />
- <Unit filename="lib/resolve_path.h" />
- <Unit filename="lib/resources.cpp" />
- <Unit filename="lib/resources.h" />
- <Unit filename="lib/return_codes.h" />
- <Unit filename="lib/shadow.cpp" />
- <Unit filename="lib/shadow.h" />
- <Unit filename="lib/soft_filter.h" />
- <Unit filename="lib/status_handler.cpp" />
- <Unit filename="lib/status_handler.h" />
- <Unit filename="lib/versioning.cpp" />
- <Unit filename="lib/versioning.h" />
- <Unit filename="lib/xml_base.cpp" />
- <Unit filename="lib/xml_base.h" />
- <Unit filename="resource.rc">
- <Option compilerVar="WINDRES" />
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="structures.cpp" />
- <Unit filename="structures.h" />
- <Unit filename="synchronization.cpp" />
- <Unit filename="synchronization.h" />
- <Unit filename="ui/batch_config.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/batch_config.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/batch_status_handler.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/batch_status_handler.h" />
- <Unit filename="ui/check_version.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/check_version.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/custom_grid.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/custom_grid.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/dir_name.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/dir_name.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/exec_finished_box.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/exec_finished_box.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/folder_history_box.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/folder_history_box.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/folder_pair.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/grid_view.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/grid_view.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/gui_generated.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/gui_generated.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/gui_status_handler.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/gui_status_handler.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/main_dlg.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/main_dlg.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/msg_popup.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/msg_popup.h" />
- <Unit filename="ui/progress_indicator.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/progress_indicator.h" />
- <Unit filename="ui/search.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/search.h" />
- <Unit filename="ui/small_dlgs.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/small_dlgs.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/sorting.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/switch_to_gui.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/sync_cfg.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/sync_cfg.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/taskbar.cpp" />
- <Unit filename="ui/taskbar.h" />
- <Unit filename="ui/tray_icon.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/tray_icon.h" />
- <Unit filename="ui/tree_view.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/tree_view.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/triple_splitter.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/triple_splitter.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="ui/wx_form_build_hide_warnings.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/app_main.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/button.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/button.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/choice_enum.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/dir_picker.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/file_drop.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/graph.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/graph.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/grid.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/grid.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/image_tools.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/mouse_move_dlg.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/mouse_move_dlg.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/pch.h">
- <Option compile="1" />
- <Option weight="0" />
- <Option target="Debug-DLL" />
- <Option target="Unit Test" />
- </Unit>
- <Unit filename="wx+/shell_execute.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/string_conv.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/toggle_button.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/tooltip.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/tooltip.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="wx+/zlib_wrap.cpp" />
- <Unit filename="wx+/zlib_wrap.h" />
- <Unit filename="zen/assert_static.h" />
- <Unit filename="zen/base64.h" />
- <Unit filename="zen/build_info.h" />
- <Unit filename="zen/com_error.h" />
- <Unit filename="zen/com_ptr.h" />
- <Unit filename="zen/com_util.h" />
- <Unit filename="zen/debug_log.h" />
- <Unit filename="zen/dir_watcher.h" />
- <Unit filename="zen/dll.h" />
- <Unit filename="zen/dst_hack.cpp" />
- <Unit filename="zen/dst_hack.h" />
- <Unit filename="zen/file_error.h" />
- <Unit filename="zen/file_handling.cpp" />
- <Unit filename="zen/file_handling.h" />
- <Unit filename="zen/file_id.cpp" />
- <Unit filename="zen/file_id.h" />
- <Unit filename="zen/file_io.cpp" />
- <Unit filename="zen/file_io.h" />
- <Unit filename="zen/file_traverser.cpp" />
- <Unit filename="zen/file_traverser.h" />
- <Unit filename="zen/fixed_list.h" />
- <Unit filename="zen/format_unit.cpp" />
- <Unit filename="zen/format_unit.h">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="zen/guid.h" />
- <Unit filename="zen/i18n.h" />
- <Unit filename="zen/int64.h" />
- <Unit filename="zen/last_error.h" />
- <Unit filename="zen/long_path_prefix.h" />
- <Unit filename="zen/notify_removal.h" />
- <Unit filename="zen/perf.h" />
- <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/scroll_window_under_cursor.cpp">
- <Option target="Release" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="zen/serialize.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/warn_static.h" />
- <Unit filename="zen/win.h" />
- <Unit filename="zen/zstring.cpp" />
- <Unit filename="zen/zstring.h" />
- <Extensions>
- <code_completion />
- <envvars />
- <debugger />
- <DoxyBlocks>
- <comment_style block="0" line="0" />
- <doxyfile_project />
- <doxyfile_build />
- <doxyfile_warnings />
- <doxyfile_output />
- <doxyfile_dot />
- <general />
- </DoxyBlocks>
- </Extensions>
- </Project>
-</CodeBlocks_project_file>
diff --git a/FreeFileSync.vcxproj b/FreeFileSync.vcxproj
index 60c622f6..5bc30a85 100644
--- a/FreeFileSync.vcxproj
+++ b/FreeFileSync.vcxproj
@@ -141,6 +141,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<MinimalRebuild>false</MinimalRebuild>
<SmallerTypeCheck>true</SmallerTypeCheck>
+ <ShowIncludes>false</ShowIncludes>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp
deleted file mode 100644
index a5f82367..00000000
--- a/RealtimeSync/RealtimeSync.cbp
+++ /dev/null
@@ -1,158 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<CodeBlocks_project_file>
- <FileVersion major="1" minor="6" />
- <Project>
- <Option title="RealtimeSync" />
- <Option makefile="makefile" />
- <Option pch_mode="2" />
- <Option compiler="gcc" />
- <Build>
- <Target title="Release">
- <Option output="../BUILD/Bin/RealtimeSync_Win32" prefix_auto="1" extension_auto="1" />
- <Option working_dir="../BUILD" />
- <Option object_output="../OBJ/RTS_Release_32_MinGW" />
- <Option type="0" />
- <Option compiler="gcc" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-O3" />
- <Add option="-DNDEBUG" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_release_lib/mswu" />
- </Compiler>
- <Linker>
- <Add option="-s" />
- <Add option="-static" />
- <Add library="libwxmsw28u_core.a" />
- <Add library="libwxmsw28u_adv.a" />
- <Add library="libwxbase28u.a" />
- <Add library="libwxpng.a" />
- <Add library="libwxzlib.a" />
- <Add library="libboost_thread-mgw47-mt-s-1_52.a" />
- <Add library="libboost_system-mgw47-mt-s-1_52.a" />
- <Add directory="C:/Programme/C++/wxWidgets/lib/mingw_release_lib" />
- </Linker>
- <ExtraCommands>
- <Add after='&quot;C:\Program Files\C++\CodeSigning\SignCode.cmd&quot; &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot;' />
- </ExtraCommands>
- </Target>
- <Target title="Debug-DLL">
- <Option output="../BUILD/Bin/RealtimeSync_Debug" prefix_auto="1" extension_auto="1" />
- <Option working_dir="../BUILD" />
- <Option object_output="../OBJ/RTS_Debug_32_MinGW" />
- <Option type="0" />
- <Option compiler="gcc" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-g" />
- <Add option="-Winvalid-pch" />
- <Add option='-include &quot;../wx+/pch.h&quot;' />
- <Add option="-D__WXDEBUG__" />
- <Add directory="C:/Program Files/C++/wxWidgets/lib/mingw_debug_dll/mswud" />
- </Compiler>
- <Linker>
- <Add library="libwxmsw28ud_core.a" />
- <Add library="libwxmsw28ud_adv.a" />
- <Add library="libwxbase28ud.a" />
- <Add library="libwxpngd.a" />
- <Add library="libwxzlibd.a" />
- <Add library="libboost_thread-mgw47-mt-sd-1_52.a" />
- <Add library="libboost_system-mgw47-mt-sd-1_52.a" />
- <Add directory="C:/Program Files/C++/wxWidgets/lib/mingw_debug_dll" />
- </Linker>
- </Target>
- </Build>
- <Compiler>
- <Add option="-Wshadow" />
- <Add option="-Winit-self" />
- <Add option="-Wswitch-enum" />
- <Add option="-Wmain" />
- <Add option="-std=c++0x" />
- <Add option="-Wall" />
- <Add option="-pipe" />
- <Add option="-mthreads" />
- <Add option="-fno-omit-frame-pointer" />
- <Add option="-std=gnu++0x" />
- <Add option='-include &quot;../zen/warn_static.h&quot;' />
- <Add option="-D__GNUWIN32__" />
- <Add option="-D__WXMSW__" />
- <Add option="-DwxUSE_UNICODE" />
- <Add option="-DFFS_WIN" />
- <Add option="-DZEN_PLATFORM_WINDOWS" />
- <Add option="-DBOOST_THREAD_NO_LIB" />
- <Add option="-DBOOST_THREAD_USE_LIB" />
- <Add option="-DWXINTL_NO_GETTEXT_MACRO" />
- <Add directory="C:/Programme/C++/wxWidgets/include" />
- <Add directory="C:/Program Files/C++/Boost" />
- <Add directory=".." />
- </Compiler>
- <ResourceCompiler>
- <Add directory="C:/Programme/C++/wxWidgets/include" />
- </ResourceCompiler>
- <Linker>
- <Add option="-mthreads" />
- <Add library="libkernel32.a" />
- <Add library="libuser32.a" />
- <Add library="libuuid.a" />
- <Add library="libcomctl32.a" />
- <Add library="libgdi32.a" />
- <Add library="libole32.a" />
- <Add library="liboleaut32.a" />
- <Add library="libcomdlg32.a" />
- <Add library="libws2_32.a" />
- <Add library="libwinspool.a" />
- <Add library="libmpr.a" />
- <Add library="libuxtheme.a" />
- <Add directory="C:/Program Files/C++/Boost/stage/lib" />
- </Linker>
- <Unit filename="../lib/localization.cpp" />
- <Unit filename="../lib/process_xml.cpp" />
- <Unit filename="../lib/resolve_path.cpp" />
- <Unit filename="../lib/xml_base.cpp" />
- <Unit filename="../structures.cpp" />
- <Unit filename="../ui/dir_name.cpp" />
- <Unit filename="../ui/dir_name.h" />
- <Unit filename="../ui/folder_history_box.cpp" />
- <Unit filename="../ui/folder_history_box.h" />
- <Unit filename="../wx+/button.cpp" />
- <Unit filename="../wx+/mouse_move_dlg.cpp" />
- <Unit filename="../wx+/pch.h">
- <Option compile="1" />
- <Option weight="0" />
- <Option target="Debug-DLL" />
- </Unit>
- <Unit filename="../zen/dir_watcher.cpp" />
- <Unit filename="../zen/dst_hack.cpp" />
- <Unit filename="../zen/file_handling.cpp" />
- <Unit filename="../zen/file_io.cpp" />
- <Unit filename="../zen/file_traverser.cpp" />
- <Unit filename="../zen/notify_removal.cpp" />
- <Unit filename="../zen/privilege.cpp" />
- <Unit filename="../zen/scroll_window_under_cursor.cpp" />
- <Unit filename="../zen/zstring.cpp" />
- <Unit filename="WxWizFrame.fbp" />
- <Unit filename="application.cpp" />
- <Unit filename="application.h" />
- <Unit filename="gui_generated.cpp" />
- <Unit filename="gui_generated.h" />
- <Unit filename="main_dlg.cpp" />
- <Unit filename="main_dlg.h" />
- <Unit filename="resource.rc">
- <Option compilerVar="WINDRES" />
- </Unit>
- <Unit filename="resources.cpp" />
- <Unit filename="resources.h" />
- <Unit filename="tray_menu.cpp" />
- <Unit filename="tray_menu.h" />
- <Unit filename="watcher.cpp" />
- <Unit filename="watcher.h" />
- <Unit filename="xml_ffs.cpp" />
- <Unit filename="xml_ffs.h" />
- <Unit filename="xml_proc.cpp" />
- <Unit filename="xml_proc.h" />
- <Extensions>
- <code_completion />
- <envvars />
- <debugger />
- </Extensions>
- </Project>
-</CodeBlocks_project_file>
diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp
index 391a1ddb..87bca60f 100644
--- a/RealtimeSync/resources.cpp
+++ b/RealtimeSync/resources.cpp
@@ -60,8 +60,8 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& name) const
{
auto it = bitmaps.find(!contains(name, L'.') ? //assume .png ending if nothing else specified
- name + L".png" :
- name);
+ name + L".png" :
+ name);
if (it != bitmaps.end())
return it->second;
else
diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp
index 3319f427..eec568ad 100644
--- a/RealtimeSync/tray_menu.cpp
+++ b/RealtimeSync/tray_menu.cpp
@@ -401,7 +401,7 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
lastChangeDetected = DirWatcher::Entry(); //make sure old name is not shown again after a directory reappears
//execute command
- auto cmdLineExp = utfCvrtTo<wxString>(expandMacros(utfCvrtTo<Zstring>(cmdLine)));
+ auto cmdLineExp = expandMacros(utfCvrtTo<Zstring>(cmdLine));
zen::shellExecute(cmdLineExp, zen::EXEC_TYPE_SYNC);
callback.clearSchedule();
}
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp
index 1380e474..9b1e5a17 100644
--- a/RealtimeSync/watcher.cpp
+++ b/RealtimeSync/watcher.cpp
@@ -72,7 +72,7 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
{
//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)))
+ while (!ftDirExists.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
statusHandler.requestUiRefresh(); //may throw!
if (!ftDirExists.get())
return WaitResult(dirnameFmt);
@@ -151,7 +151,7 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
}
}
- boost::this_thread::sleep(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL));
+ boost::this_thread::sleep(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL / 2));
statusHandler.requestUiRefresh(true); //throw ?: may start sync at this presumably idle time
}
}
@@ -178,7 +178,7 @@ void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCal
//2. check dir existence
return zen::dirExists(dirnameFmt);
});
- while (!ftDirExisting.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL)))
+ while (!ftDirExisting.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL / 2)))
statusHandler.requestUiRefresh(); //may throw!
if (!ftDirExisting.get())
@@ -191,10 +191,11 @@ void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCal
return;
//wait some time...
- assert_static(1000 * CHECK_DIR_INTERVAL % UI_UPDATE_INTERVAL == 0);
- for (int i = 0; i < 1000 * CHECK_DIR_INTERVAL / UI_UPDATE_INTERVAL; ++i)
+ const int refreshInterval = UI_UPDATE_INTERVAL / 2;
+ assert_static(1000 * CHECK_DIR_INTERVAL % refreshInterval == 0);
+ for (int i = 0; i < 1000 * CHECK_DIR_INTERVAL / refreshInterval; ++i)
{
- boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL));
+ boost::this_thread::sleep(boost::posix_time::milliseconds(refreshInterval));
statusHandler.requestUiRefresh();
}
}
diff --git a/algorithm.cpp b/algorithm.cpp
index affc5bd1..0c47410a 100644
--- a/algorithm.cpp
+++ b/algorithm.cpp
@@ -12,12 +12,13 @@
#include <zen/recycler.h>
#include <zen/stl_tools.h>
#include <zen/scope_guard.h>
-//#include <wx/msgdlg.h>
+#include <zen/thread.h>
#include "lib/resources.h"
#include "lib/norm_filter.h"
#include "lib/db_file.h"
#include "lib/cmp_filetime.h"
#include "lib/norm_filter.h"
+#include "process_callback.h" //for UI_UPDATE_INTERVAL
using namespace zen;
using namespace std::rel_ops;
@@ -53,19 +54,22 @@ private:
void operator()(FileMapping& fileObj) const
{
- switch (fileObj.getCategory())
+ const CompareFilesResult cat = fileObj.getCategory();
+
+ //##################### schedule old temporary files for deletion ####################
+ if (cat == FILE_LEFT_SIDE_ONLY && endsWith(fileObj.getShortName<LEFT_SIDE>(), TEMP_FILE_ENDING))
+ return fileObj.setSyncDir(SYNC_DIR_LEFT);
+ else if (cat == FILE_RIGHT_SIDE_ONLY && endsWith(fileObj.getShortName<RIGHT_SIDE>(), TEMP_FILE_ENDING))
+ return fileObj.setSyncDir(SYNC_DIR_RIGHT);
+ //####################################################################################
+
+ switch (cat)
{
case FILE_LEFT_SIDE_ONLY:
- if (endsWith(fileObj.getShortName<LEFT_SIDE>(), zen::TEMP_FILE_ENDING))
- fileObj.setSyncDir(SYNC_DIR_LEFT); //schedule potentially existing temporary files for deletion
- else
- fileObj.setSyncDir(dirCfg.exLeftSideOnly);
+ fileObj.setSyncDir(dirCfg.exLeftSideOnly);
break;
case FILE_RIGHT_SIDE_ONLY:
- if (endsWith(fileObj.getShortName<RIGHT_SIDE>(), zen::TEMP_FILE_ENDING))
- fileObj.setSyncDir(SYNC_DIR_RIGHT); //schedule potentially existing temporary files for deletion
- else
- fileObj.setSyncDir(dirCfg.exRightSideOnly);
+ fileObj.setSyncDir(dirCfg.exRightSideOnly);
break;
case FILE_RIGHT_NEWER:
fileObj.setSyncDir(dirCfg.rightNewer);
@@ -123,7 +127,16 @@ private:
void operator()(DirMapping& dirObj) const
{
- switch (dirObj.getDirCategory())
+ const CompareDirResult cat = dirObj.getDirCategory();
+
+ //########### schedule abandoned temporary recycle bin directory for deletion ##########
+ if (cat == DIR_LEFT_SIDE_ONLY && endsWith(dirObj.getShortName<LEFT_SIDE>(), TEMP_FILE_ENDING))
+ return setSyncDirectionRec(SYNC_DIR_LEFT, dirObj); //
+ else if (cat == DIR_RIGHT_SIDE_ONLY && endsWith(dirObj.getShortName<RIGHT_SIDE>(), TEMP_FILE_ENDING))
+ return setSyncDirectionRec(SYNC_DIR_RIGHT, dirObj); //don't recurse below!
+ //#######################################################################################
+
+ switch (cat)
{
case DIR_LEFT_SIDE_ONLY:
dirObj.setSyncDir(dirCfg.exLeftSideOnly);
@@ -148,8 +161,8 @@ private:
const DirectionSet dirCfg;
};
-
//---------------------------------------------------------------------------------------------------------------
+
struct AllEqual //test if non-equal items exist in scanned data
{
bool operator()(const HierarchyObject& hierObj) const
@@ -385,15 +398,9 @@ private:
//##################### schedule old temporary files for deletion ####################
if (cat == FILE_LEFT_SIDE_ONLY && endsWith(fileObj.getShortName<LEFT_SIDE>(), TEMP_FILE_ENDING))
- {
- fileObj.setSyncDir(SYNC_DIR_LEFT);
- return;
- }
+ return fileObj.setSyncDir(SYNC_DIR_LEFT);
else if (cat == FILE_RIGHT_SIDE_ONLY && endsWith(fileObj.getShortName<RIGHT_SIDE>(), TEMP_FILE_ENDING))
- {
- fileObj.setSyncDir(SYNC_DIR_RIGHT);
- return;
- }
+ return fileObj.setSyncDir(SYNC_DIR_RIGHT);
//####################################################################################
//try to find corresponding database entry
@@ -466,6 +473,13 @@ private:
{
const CompareDirResult cat = dirObj.getDirCategory();
+ //########### schedule abandoned temporary recycle bin directory for deletion ##########
+ if (cat == DIR_LEFT_SIDE_ONLY && endsWith(dirObj.getShortName<LEFT_SIDE>(), TEMP_FILE_ENDING))
+ return setSyncDirectionRec(SYNC_DIR_LEFT, dirObj); //
+ else if (cat == DIR_RIGHT_SIDE_ONLY && endsWith(dirObj.getShortName<RIGHT_SIDE>(), TEMP_FILE_ENDING))
+ return setSyncDirectionRec(SYNC_DIR_RIGHT, dirObj); //don't recurse below!
+ //#######################################################################################
+
//try to find corresponding database entry
const InSyncDir::DirList::value_type* dbEntry = nullptr;
if (dbContainer)
@@ -527,9 +541,10 @@ private:
{
auto iterPair = cnt.equal_range(key); //since file id is already unique, we expect a single-element range at most
auto it = std::find_if(iterPair.first, iterPair.second,
- [&](const typename Container::value_type& item)
+ [&](const typename Container::value_type& item)
{
- return sameFileTime(std::get<0>(item.first), std::get<0>(key), 2); //respect 2 second FAT/FAT32 precision
+ return sameFileTime(std::get<0>(item.first), std::get<0>(key), 2); //respect 2 second FAT/FAT32 precision!
+ //the file time could be inferred from the source side after a file copy while a slightly different time is stored on a FAT32 disk!
});
return it == iterPair.second ? cnt.end() : it;
}
@@ -754,7 +769,6 @@ void zen::setSyncDirectionRec(SyncDirection newDirection, FileSystemObject& fsOb
fsObj.accept(recurse);
}
-
//--------------- functions related to filtering ------------------------------------------------------------------------------------
template <bool include>
@@ -1192,51 +1206,139 @@ bool tryReportingError(Function cmd, DeleteFilesHandler& handler) //return "true
}
}
+#ifdef FFS_WIN
+//recycleBinStatus() blocks seriously if recycle bin is really full and drive is slow
+StatusRecycler recycleBinStatusUpdating(const Zstring& dirname, DeleteFilesHandler& callback)
+{
+ const std::wstring msg = replaceCpy(_("Checking recycle bin availability for folder %x..."), L"%x", fmtFileName(dirname), false);
+
+ auto ft = async([=] { return recycleBinStatus(dirname); });
+ while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
+ callback.reportStatus(msg); //may throw!
+ return ft.get();
+}
+#endif
+
-struct RemoveCallbackImpl : public zen::CallbackRemoveDir
+template <SelectedSide side>
+void categorize(const std::set<FileSystemObject*>& rowsIn,
+ std::vector<FileSystemObject*>& deletePermanent,
+ std::vector<FileSystemObject*>& deleteRecyler,
+ bool useRecycleBin,
+ std::map<Zstring, bool, LessFilename>& hasRecyclerBuffer,
+ DeleteFilesHandler& callback)
{
- RemoveCallbackImpl(DeleteFilesHandler& handler) : handler_(handler) {}
+ auto hasRecycler = [&](const FileSystemObject& fsObj) -> bool
+ {
+#ifdef FFS_WIN
+ const Zstring& baseDirPf = fsObj.root().getBaseDirPf<side>();
- virtual void notifyFileDeletion(const Zstring& filename) { handler_.notifyDeletion(filename); }
- virtual void notifyDirDeletion (const Zstring& dirname) { handler_.notifyDeletion(dirname); }
+ auto it = hasRecyclerBuffer.find(baseDirPf);
+ if (it != hasRecyclerBuffer.end())
+ return it->second;
+ return hasRecyclerBuffer.insert(std::make_pair(baseDirPf, recycleBinStatusUpdating(baseDirPf, callback) == STATUS_REC_EXISTS)).first->second;
+#else
+ return true;
+#endif
+ };
-private:
- DeleteFilesHandler& handler_;
-};
+ for (auto it = rowsIn.begin(); it != rowsIn.end(); ++it)
+ if (!(*it)->isEmpty<side>())
+ {
+ if (useRecycleBin && hasRecycler(**it)) //Windows' ::SHFileOperation() will delete permanently anyway, but we have a superior deletion routine
+ deleteRecyler.push_back(*it);
+ else
+ deletePermanent.push_back(*it);
+ }
+}
template <SelectedSide side>
-struct PermanentDeleter : public FSObjectVisitor //throw FileError
+struct ItemDeleter : public FSObjectVisitor //throw FileError, but nothrow constructor!!!
{
- PermanentDeleter(DeleteFilesHandler& handler) : remCallback(handler) {}
+ ItemDeleter(bool useRecycleBin, DeleteFilesHandler& handler) :
+ handler_(handler), useRecycleBin_(useRecycleBin), remCallback(*this)
+ {
+ if (useRecycleBin_)
+ {
+ txtRemovingFile = _("Moving file %x to recycle bin" );
+ txtRemovingDirectory = _("Moving folder %x to recycle bin" );
+ txtRemovingSymlink = _("Moving symbolic link %x to recycle bin");
+ }
+ else
+ {
+ txtRemovingFile = _("Deleting file %x" );
+ txtRemovingDirectory = _("Deleting folder %x" );
+ txtRemovingSymlink = _("Deleting symbolic link %x");
+ }
+ }
virtual void visit(const FileMapping& fileObj)
{
- if (zen::removeFile(fileObj.getFullName<side>())) //throw FileError
- remCallback.notifyFileDeletion(fileObj.getFullName<side>());
+ notifyFileDeletion(fileObj.getFullName<side>());
+
+ if (useRecycleBin_)
+ zen::recycleOrDelete(fileObj.getFullName<side>()); //throw FileError
+ else
+ zen::removeFile(fileObj.getFullName<side>()); //throw FileError
}
virtual void visit(const SymLinkMapping& linkObj)
{
- switch (linkObj.getLinkType<side>())
- {
- case LinkDescriptor::TYPE_DIR:
- zen::removeDirectory(linkObj.getFullName<side>(), &remCallback); //throw FileError
- break;
- case LinkDescriptor::TYPE_FILE:
- if (zen::removeFile(linkObj.getFullName<side>())) //throw FileError
- remCallback.notifyFileDeletion(linkObj.getFullName<side>());
- break;
- }
+ notifySymlinkDeletion(linkObj.getFullName<side>());
+
+ if (useRecycleBin_)
+ zen::recycleOrDelete(linkObj.getFullName<side>()); //throw FileError
+ else
+ switch (linkObj.getLinkType<side>())
+ {
+ case LinkDescriptor::TYPE_DIR:
+ zen::removeDirectory(linkObj.getFullName<side>()); //throw FileError
+ break;
+ case LinkDescriptor::TYPE_FILE:
+ zen::removeFile(linkObj.getFullName<side>()); //throw FileError
+ break;
+ }
}
virtual void visit(const DirMapping& dirObj)
{
- zen::removeDirectory(dirObj.getFullName<side>(), &remCallback); //throw FileError
+ notifyDirectoryDeletion(dirObj.getFullName<side>()); //notfied twice! see RemoveCallbackImpl -> no big deal
+
+ if (useRecycleBin_)
+ zen::recycleOrDelete(dirObj.getFullName<side>()); //throw FileError
+ else
+ zen::removeDirectory(dirObj.getFullName<side>(), &remCallback); //throw FileError
}
private:
+ struct RemoveCallbackImpl : public zen::CallbackRemoveDir
+ {
+ RemoveCallbackImpl(ItemDeleter& itemDeleter) : itemDeleter_(itemDeleter) {}
+
+ virtual void onBeforeFileDeletion(const Zstring& filename) { itemDeleter_.notifyFileDeletion (filename); }
+ virtual void onBeforeDirDeletion (const Zstring& dirname) { itemDeleter_.notifyDirectoryDeletion(dirname ); }
+
+ private:
+ ItemDeleter& itemDeleter_;
+ };
+
+ void notifyFileDeletion (const Zstring& objName) { notifyItemDeletion(txtRemovingFile , objName); }
+ void notifyDirectoryDeletion(const Zstring& objName) { notifyItemDeletion(txtRemovingDirectory, objName); }
+ void notifySymlinkDeletion (const Zstring& objName) { notifyItemDeletion(txtRemovingSymlink , objName); }
+
+ void notifyItemDeletion(const std::wstring& statusText, const Zstring& objName)
+ {
+ handler_.reportStatus(replaceCpy(statusText, L"%x", fmtFileName(objName)));
+ }
+
+ DeleteFilesHandler& handler_;
+ const bool useRecycleBin_;
RemoveCallbackImpl remCallback;
+
+ std::wstring txtRemovingFile;
+ std::wstring txtRemovingDirectory;
+ std::wstring txtRemovingSymlink;
};
@@ -1245,64 +1347,21 @@ void deleteFromGridAndHDOneSide(std::vector<FileSystemObject*>& ptrList,
bool useRecycleBin,
DeleteFilesHandler& handler)
{
+ ItemDeleter<side> deleter(useRecycleBin, handler);
+
for (auto it = ptrList.begin(); it != ptrList.end(); ++it) //VS 2010 bug prevents replacing this by std::for_each + lamba
{
FileSystemObject& fsObj = **it; //all pointers are required(!) to be bound
- if (fsObj.isEmpty<side>()) //element may be implicitly deleted, e.g. if parent folder was deleted first
- continue;
-
- tryReportingError([&]
+ if (!fsObj.isEmpty<side>()) //element may be implicitly deleted, e.g. if parent folder was deleted first
+ tryReportingError([&]
{
- if (useRecycleBin)
- {
- if (zen::recycleOrDelete(fsObj.getFullName<side>())) //throw FileError
- handler.notifyDeletion(fsObj.getFullName<side>());
- }
- else
- {
- PermanentDeleter<side> delPerm(handler); //throw FileError
- fsObj.accept(delPerm);
- }
-
+ fsObj.accept(deleter); //throw FileError
fsObj.removeObject<side>(); //if directory: removes recursively!
}, handler);
}
}
-
-
-template <SelectedSide side>
-void categorize(const std::set<FileSystemObject*>& rowsIn,
- std::vector<FileSystemObject*>& deletePermanent,
- std::vector<FileSystemObject*>& deleteRecyler,
- bool useRecycleBin,
- std::map<Zstring, bool, LessFilename>& hasRecyclerBuffer)
-{
- auto hasRecycler = [&](const FileSystemObject& fsObj) -> bool
- {
-#ifdef FFS_WIN
- const Zstring& baseDirPf = fsObj.root().getBaseDirPf<side>();
-
- auto it = hasRecyclerBuffer.find(baseDirPf);
- if (it != hasRecyclerBuffer.end())
- return it->second;
- return hasRecyclerBuffer.insert(std::make_pair(baseDirPf, recycleBinStatus(baseDirPf) == STATUS_REC_EXISTS)).first->second;
-#else
- return true;
-#endif
- };
-
- for (auto it = rowsIn.begin(); it != rowsIn.end(); ++it)
- if (!(*it)->isEmpty<side>())
- {
- if (useRecycleBin && hasRecycler(**it)) //Windows' ::SHFileOperation() will delete permanently anyway, but we have a superior deletion routine
- deleteRecyler.push_back(*it);
- else
- deletePermanent.push_back(*it);
- }
-}
}
-
void zen::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDeleteOnLeft, //refresh GUI grid after deletion to remove invalid rows
const std::vector<FileSystemObject*>& rowsToDeleteOnRight, //all pointers need to be bound!
FolderComparison& folderCmp, //attention: rows will be physically deleted!
@@ -1378,8 +1437,8 @@ void zen::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDelete
std::vector<FileSystemObject*> deleteRecylerRight;
std::map<Zstring, bool, LessFilename> hasRecyclerBuffer;
- categorize<LEFT_SIDE >(deleteLeft, deletePermanentLeft, deleteRecylerLeft, useRecycleBin, hasRecyclerBuffer);
- categorize<RIGHT_SIDE>(deleteRight, deletePermanentRight, deleteRecylerRight, useRecycleBin, hasRecyclerBuffer);
+ categorize<LEFT_SIDE >(deleteLeft, deletePermanentLeft, deleteRecylerLeft, useRecycleBin, hasRecyclerBuffer, statusHandler);
+ categorize<RIGHT_SIDE>(deleteRight, deletePermanentRight, deleteRecylerRight, useRecycleBin, hasRecyclerBuffer, statusHandler);
//windows: check if recycle bin really exists; if not, Windows will silently delete, which is wrong
if (useRecycleBin &&
diff --git a/algorithm.h b/algorithm.h
index 3fcd9436..1c29a5bd 100644
--- a/algorithm.h
+++ b/algorithm.h
@@ -36,15 +36,13 @@ void setActiveStatus(bool newStatus, FileSystemObject& fsObj); //activate or
//manual deletion of files on main grid
-std::pair<Zstring, int> deleteFromGridAndHDPreview( //returns wxString with elements to be deleted and total count of selected(!) objects, NOT total files/dirs!
+std::pair<Zstring, int> deleteFromGridAndHDPreview( //returns string with elements to be deleted and total count of selected(!) objects, NOT total files/dirs!
const std::vector<FileSystemObject*>& selectionLeft, //all pointers need to be bound!
const std::vector<FileSystemObject*>& selectionRight, //
bool deleteOnBothSides);
-class DeleteFilesHandler
+struct DeleteFilesHandler
{
-public:
- DeleteFilesHandler() {}
virtual ~DeleteFilesHandler() {}
enum Response
@@ -54,9 +52,7 @@ public:
};
virtual Response reportError (const std::wstring& msg) = 0;
virtual void reportWarning(const std::wstring& msg, bool& warningActive) = 0;
-
- //virtual void totalFilesToDelete(int objectsTotal) = 0; //informs about the total number of files to be deleted
- virtual void notifyDeletion(const Zstring& currentObject) = 0; //called for each file/folder that has been deleted
+ virtual void reportStatus (const std::wstring& msg) = 0;
};
void deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDeleteOnLeft, //refresh GUI grid after deletion to remove invalid rows
const std::vector<FileSystemObject*>& rowsToDeleteOnRight, //all pointers need to be bound!
diff --git a/comparison.cpp b/comparison.cpp
index 0832a5bf..56ec2735 100644
--- a/comparison.cpp
+++ b/comparison.cpp
@@ -112,7 +112,7 @@ void determineExistentDirs(const std::set<Zstring, LessFilename>& dirnames,
const Zstring& dirname = *it;
callback.reportStatus(replaceCpy(_("Searching for folder %x..."), L"%x", fmtFileName(dirname), false));
- while (boost::get_system_time() < timeMax && !iterCheckDir->timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)))
+ while (boost::get_system_time() < timeMax && !iterCheckDir->timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
callback.requestUiRefresh(); //may throw!
//only (still) existing files should be included in the list
@@ -192,10 +192,10 @@ std::wstring checkFolderDependency(const std::vector<FolderPairCfg>& folderPairs
if (!dependentDirs.empty())
{
warningMsg = _("Directories are dependent! Be careful when setting up synchronization rules:");
- for (auto i = dependentDirs.begin(); i != dependentDirs.end(); ++i)
+ for (auto it = dependentDirs.begin(); it != dependentDirs.end(); ++it)
warningMsg += L"\n\n" +
- fmtFileName(i->first) + L"\n" +
- fmtFileName(i->second);
+ fmtFileName(it->first) + L"\n" +
+ fmtFileName(it->second);
}
return warningMsg;
}
@@ -205,40 +205,41 @@ std::wstring checkFolderDependency(const std::vector<FolderPairCfg>& folderPairs
class CmpCallbackImpl : public CompareCallback
{
public:
- CmpCallbackImpl(ProcessCallback& pc, UInt64& bytesReported) :
+ CmpCallbackImpl(ProcessCallback& pc, Int64& bytesReported) :
pc_(pc),
bytesReported_(bytesReported) {}
- virtual void updateCompareStatus(UInt64 totalBytes)
+ virtual void updateCompareStatus(Int64 bytesDelta)
{
//inform about the (differential) processed amount of data
- pc_.updateProcessedData(0, to<Int64>(totalBytes) - to<Int64>(bytesReported_)); //throw()! -> this ensures client and service provider are in sync!
- bytesReported_ = totalBytes; //
+ pc_.updateProcessedData(0, bytesDelta); //throw()! -> ensure client and service provider are in sync!
+ bytesReported_ += bytesDelta; //
pc_.requestUiRefresh(); //may throw
}
private:
ProcessCallback& pc_;
- UInt64& bytesReported_;
+ Int64& bytesReported_;
};
-bool filesHaveSameContentUpdating(const Zstring& filename1, const Zstring& filename2, UInt64 totalBytesToCmp, ProcessCallback& pc) //throw FileError
+bool filesHaveSameContentUpdating(const Zstring& filename1, const Zstring& filename2, Int64 expectedBytesToCmp, ProcessCallback& pc) //throw FileError
{
- UInt64 bytesReported; //amount of bytes that have been compared and communicated to status handler
+ Int64 bytesReported; //amount of bytes that have been compared and communicated to status handler
- //in error situation: undo communication of processed amount of data
- zen::ScopeGuard guardStatistics = zen::makeGuard([&] { pc.updateProcessedData(0, -1 * to<Int64>(bytesReported)); });
+ //error = unexpected increase of total workload
+ zen::ScopeGuard guardStatistics = zen::makeGuard([&] { pc.updateTotalData(0, bytesReported); });
CmpCallbackImpl callback(pc, bytesReported);
bool sameContent = filesHaveSameContent(filename1, filename2, callback); //throw FileError
- //inform about the (remaining) processed amount of data
- pc.updateProcessedData(0, to<Int64>(totalBytesToCmp) - to<Int64>(bytesReported));
- bytesReported = totalBytesToCmp;
-
guardStatistics.dismiss();
+
+ //update statistics to consider the real amount of data processed: consider short-cut behavior if first bytes differ!
+ if (bytesReported != expectedBytesToCmp)
+ pc.updateTotalData(0, bytesReported - expectedBytesToCmp);
+
return sameContent;
}
}
@@ -286,7 +287,7 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& keysToRead,
virtual void reportStatus(const std::wstring& statusMsg, int itemsTotal)
{
- callback_.updateProcessedData(itemsTotal - itemsReported, 0); //processed data is communicated in subfunctions!
+ callback_.updateProcessedData(itemsTotal - itemsReported, 0); //processed bytes are reported in subfunctions!
itemsReported = itemsTotal;
callback_.reportStatus(statusMsg); //may throw
@@ -316,7 +317,7 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& keysToRead,
fillBuffer(keysToRead, //in
directoryBuffer, //out
cb,
- UI_UPDATE_INTERVAL / 4); //every ~25 ms
+ UI_UPDATE_INTERVAL / 2); //every ~50 ms
}
@@ -331,7 +332,7 @@ void zen::compare(size_t fileTimeTolerance,
//specify process and resource handling priorities
std::unique_ptr<ScheduleForBackgroundProcessing> backgroundPrio;
if (runWithBackgroundPriority)
- backgroundPrio.reset(new ScheduleForBackgroundProcessing);
+ backgroundPrio = make_unique<ScheduleForBackgroundProcessing>();
//prevent operating system going into sleep state
PreventStandby dummy2;
@@ -699,7 +700,7 @@ void ComparisonBuffer::compareByContent(std::vector<std::pair<FolderPairCfg, Bas
{
if (filesHaveSameContentUpdating(fileObj->getFullName<LEFT_SIDE>(), //throw FileError
fileObj->getFullName<RIGHT_SIDE>(),
- fileObj->getFileSize<LEFT_SIDE >(),
+ to<Int64>(fileObj->getFileSize<LEFT_SIDE>()),
callback_))
{
//Caveat:
@@ -715,7 +716,7 @@ void ComparisonBuffer::compareByContent(std::vector<std::pair<FolderPairCfg, Bas
else
fileObj->setCategory<FILE_DIFFERENT>();
- callback_.updateProcessedData(1, 0); //processed data is communicated in subfunctions!
+ callback_.updateProcessedData(1, 0); //processed bytes are reported in subfunctions!
}, callback_))
fileObj->setCategoryConflict(_("Conflict detected:") + L"\n" + _("Comparing files by content failed."));
diff --git a/file_hierarchy.h b/file_hierarchy.h
index 8f4b1afb..f51e76bb 100644
--- a/file_hierarchy.h
+++ b/file_hierarchy.h
@@ -721,8 +721,7 @@ const Zstring& FileSystemObject::getShortName<RIGHT_SIDE>() const
}
-template <SelectedSide side>
-inline
+template <SelectedSide side> inline
Zstring FileSystemObject::getRelativeName() const
{
return isEmpty<side>() ? Zstring() : parent_.getObjRelativeNamePf() + getShortName<side>();
@@ -743,8 +742,7 @@ Zstring FileSystemObject::getObjShortName() const
}
-template <SelectedSide side>
-inline
+template <SelectedSide side> inline
Zstring FileSystemObject::getFullName() const
{
return isEmpty<side>() ? Zstring() : getBaseDirPf<side>() + parent_.getObjRelativeNamePf() + getShortName<side>();
diff --git a/lib/binary.cpp b/lib/binary.cpp
index 10994cc9..4ef30c15 100644
--- a/lib/binary.cpp
+++ b/lib/binary.cpp
@@ -85,7 +85,6 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
FileInput file2(filename2); //
BufferSize bufferSize;
- UInt64 bytesCompared;
TickVal lastDelayViolation = getTicks();
@@ -96,14 +95,19 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
const TickVal startTime = getTicks();
- const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError()
- const size_t length2 = file2.read(&memory2[0], bufferSize); //
+ const size_t length1 = file1.read(&memory1[0], bufferSize); //throw FileError()
+ const size_t length2 = file2.read(&memory2[0], bufferSize); //returns actual number of bytes read
+ //send progress updates immediately after reading to reliably allow speed calculations for our clients!
+ callback.updateCompareStatus(to<Int64>(std::max(length1, length2)));
- const TickVal now = getTicks();
+ if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
+ return false;
//-------- dynamically set buffer size to keep callback interval between 100 - 500ms ---------------------
if (TICKS_PER_SEC > 0)
{
+ const TickVal now = getTicks();
+
const std::int64_t loopTime = dist(startTime, now) * 1000 / TICKS_PER_SEC; //unit: [ms]
if (loopTime < 100)
{
@@ -120,12 +124,6 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
}
}
//------------------------------------------------------------------------------------------------
-
- if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
- return false;
-
- bytesCompared += length1;
- callback.updateCompareStatus(bytesCompared); //send progress updates
}
while (!file1.eof());
diff --git a/lib/binary.h b/lib/binary.h
index 83409e19..8a4abe6b 100644
--- a/lib/binary.h
+++ b/lib/binary.h
@@ -16,7 +16,7 @@ namespace zen
struct CompareCallback
{
virtual ~CompareCallback() {}
- virtual void updateCompareStatus(UInt64 totalBytes) = 0;
+ virtual void updateCompareStatus(Int64 bytesDelta) = 0;
};
bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError
diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h
index a02facad..306c9ab9 100644
--- a/lib/dir_exist_async.h
+++ b/lib/dir_exist_async.h
@@ -31,7 +31,7 @@ bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, Proces
//2. check dir existence
return zen::dirExists(dirname);
});
- while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)))
+ while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
procCallback.requestUiRefresh(); //may throw!
return ft.get();
}
diff --git a/lib/localization.cpp b/lib/localization.cpp
index 47ed1881..78e03545 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -28,23 +28,22 @@ namespace
class FFSLocale : public TranslationHandler
{
public:
- FFSLocale(const wxString& filename, wxLanguage languageId); //throw lngfile::ParsingError, PluralForm::ParsingError
+ FFSLocale(const wxString& filename, wxLanguage languageId); //throw lngfile::ParsingError, parse_plural::ParsingError
wxLanguage langId() const { return langId_; }
virtual std::wstring translate(const std::wstring& text)
{
//look for translation in buffer table
- const Translation::const_iterator it = transMapping.find(text);
- if (it != transMapping.end())
+ auto it = transMapping.find(text);
+ if (it != transMapping.end() && !it->second.empty())
return it->second;
-
return text; //fallback
}
virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n)
{
- TranslationPlural::const_iterator it = transMappingPl.find(std::make_pair(singular, plural));
+ auto it = transMappingPl.find(std::make_pair(singular, plural));
if (it != transMappingPl.end())
{
const int formNo = pluralParser->getForm(n);
@@ -55,17 +54,17 @@ public:
}
private:
- typedef std::map<std::wstring, std::wstring> Translation;
+ typedef hash_map<std::wstring, std::wstring> Translation; //hash_map is 15% faster than std::map on GCC
typedef std::map<std::pair<std::wstring, std::wstring>, std::vector<std::wstring> > TranslationPlural;
Translation transMapping; //map original text |-> translation
TranslationPlural transMappingPl;
- std::unique_ptr<PluralForm> pluralParser;
+ std::unique_ptr<parse_plural::PluralForm> pluralParser; //bound!
wxLanguage langId_;
};
-FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, PluralForm::ParsingError
+FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, parse_plural::ParsingError
{
std::string inputStream;
try
@@ -86,7 +85,6 @@ FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(
{
const std::wstring original = utfCvrtTo<std::wstring>(i->first);
const std::wstring translation = utfCvrtTo<std::wstring>(i->second);
- assert(!translation.empty());
transMapping.insert(std::make_pair(original, translation));
}
@@ -100,13 +98,10 @@ FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(
for (lngfile::PluralForms::const_iterator j = plForms.begin(); j != plForms.end(); ++j)
plFormsWide.push_back(utfCvrtTo<std::wstring>(*j));
- assert(!plFormsWide.empty());
-
transMappingPl.insert(std::make_pair(std::make_pair(singular, plural), plFormsWide));
}
- pluralParser.reset(new PluralForm(header.pluralDefinition)); //throw PluralForm::ParsingError
-}
+ pluralParser.reset(new parse_plural::PluralForm(header.pluralDefinition)); //throw parse_plural::ParsingError
}
@@ -151,6 +146,7 @@ struct LessTranslation : public std::binary_function<ExistingTranslations::Entry
#endif
}
};
+}
ExistingTranslations::ExistingTranslations()
@@ -173,10 +169,10 @@ ExistingTranslations::ExistingTranslations()
traverseFolder(zen::getResourceDir() + Zstr("Languages"), //throw();
traverseCallback);
- for (auto i = lngFiles.begin(); i != lngFiles.end(); ++i)
+ for (auto it = lngFiles.begin(); it != lngFiles.end(); ++it)
try
{
- std::string stream = loadStream(*i); //throw XmlFileError
+ std::string stream = loadStream(*it); //throw XmlFileError
try
{
lngfile::TransHeader lngHeader;
@@ -191,7 +187,7 @@ ExistingTranslations::ExistingTranslations()
ExistingTranslations::Entry newEntry;
newEntry.languageID = locInfo->Language;
newEntry.languageName = utfCvrtTo<wxString>(lngHeader.languageName);
- newEntry.languageFile = utfCvrtTo<wxString>(*i);
+ newEntry.languageFile = utfCvrtTo<wxString>(*it);
newEntry.translatorName = utfCvrtTo<wxString>(lngHeader.translatorName);
newEntry.languageFlag = utfCvrtTo<wxString>(lngHeader.flagFile);
locMapping.push_back(newEntry);
@@ -205,12 +201,59 @@ ExistingTranslations::ExistingTranslations()
}
+const std::vector<ExistingTranslations::Entry>& ExistingTranslations::get()
+{
+ static ExistingTranslations instance;
+ return instance.locMapping;
+}
+
+
namespace
{
wxLanguage mapLanguageDialect(wxLanguage language)
{
- switch (static_cast<int>(language)) //map language dialects
+ switch (static_cast<int>(language)) //avoid enumeration value wxLANGUAGE_*' not handled in switch [-Wswitch-enum]
{
+ //variants of wxLANGUAGE_ARABIC
+ case wxLANGUAGE_ARABIC_ALGERIA:
+ case wxLANGUAGE_ARABIC_BAHRAIN:
+ case wxLANGUAGE_ARABIC_EGYPT:
+ case wxLANGUAGE_ARABIC_IRAQ:
+ case wxLANGUAGE_ARABIC_JORDAN:
+ case wxLANGUAGE_ARABIC_KUWAIT:
+ case wxLANGUAGE_ARABIC_LEBANON:
+ case wxLANGUAGE_ARABIC_LIBYA:
+ case wxLANGUAGE_ARABIC_MOROCCO:
+ case wxLANGUAGE_ARABIC_OMAN:
+ case wxLANGUAGE_ARABIC_QATAR:
+ case wxLANGUAGE_ARABIC_SAUDI_ARABIA:
+ case wxLANGUAGE_ARABIC_SUDAN:
+ case wxLANGUAGE_ARABIC_SYRIA:
+ case wxLANGUAGE_ARABIC_TUNISIA:
+ case wxLANGUAGE_ARABIC_UAE:
+ case wxLANGUAGE_ARABIC_YEMEN:
+ return wxLANGUAGE_ARABIC;
+
+ //variants of wxLANGUAGE_ENGLISH_UK
+ case wxLANGUAGE_ENGLISH_AUSTRALIA:
+ case wxLANGUAGE_ENGLISH_NEW_ZEALAND:
+ case wxLANGUAGE_ENGLISH_TRINIDAD:
+ case wxLANGUAGE_ENGLISH_CARIBBEAN:
+ case wxLANGUAGE_ENGLISH_JAMAICA:
+ case wxLANGUAGE_ENGLISH_BELIZE:
+ case wxLANGUAGE_ENGLISH_EIRE:
+ case wxLANGUAGE_ENGLISH_SOUTH_AFRICA:
+ case wxLANGUAGE_ENGLISH_ZIMBABWE:
+ case wxLANGUAGE_ENGLISH_BOTSWANA:
+ case wxLANGUAGE_ENGLISH_DENMARK:
+ return wxLANGUAGE_ENGLISH_UK;
+
+ //variants of wxLANGUAGE_ENGLISH_US
+ case wxLANGUAGE_ENGLISH:
+ case wxLANGUAGE_ENGLISH_CANADA:
+ case wxLANGUAGE_ENGLISH_PHILIPPINES:
+ return wxLANGUAGE_ENGLISH_US;
+
//variants of wxLANGUAGE_GERMAN
case wxLANGUAGE_GERMAN_AUSTRIAN:
case wxLANGUAGE_GERMAN_BELGIUM:
@@ -281,6 +324,7 @@ wxLanguage mapLanguageDialect(wxLanguage language)
case wxLANGUAGE_NORWEGIAN_NYNORSK:
return wxLANGUAGE_NORWEGIAN_BOKMAL;
+ //languages without variants:
//case wxLANGUAGE_CZECH:
//case wxLANGUAGE_DANISH:
//case wxLANGUAGE_FINNISH:
@@ -296,41 +340,6 @@ wxLanguage mapLanguageDialect(wxLanguage language)
//case wxLANGUAGE_KOREAN:
//case wxLANGUAGE_UKRAINIAN:
//case wxLANGUAGE_CROATIAN:
-
- //variants of wxLANGUAGE_ARABIC
- case wxLANGUAGE_ARABIC_ALGERIA:
- case wxLANGUAGE_ARABIC_BAHRAIN:
- case wxLANGUAGE_ARABIC_EGYPT:
- case wxLANGUAGE_ARABIC_IRAQ:
- case wxLANGUAGE_ARABIC_JORDAN:
- case wxLANGUAGE_ARABIC_KUWAIT:
- case wxLANGUAGE_ARABIC_LEBANON:
- case wxLANGUAGE_ARABIC_LIBYA:
- case wxLANGUAGE_ARABIC_MOROCCO:
- case wxLANGUAGE_ARABIC_OMAN:
- case wxLANGUAGE_ARABIC_QATAR:
- case wxLANGUAGE_ARABIC_SAUDI_ARABIA:
- case wxLANGUAGE_ARABIC_SUDAN:
- case wxLANGUAGE_ARABIC_SYRIA:
- case wxLANGUAGE_ARABIC_TUNISIA:
- case wxLANGUAGE_ARABIC_UAE:
- case wxLANGUAGE_ARABIC_YEMEN:
- return wxLANGUAGE_ARABIC;
-
- //variants of wxLANGUAGE_ENGLISH_UK
- case wxLANGUAGE_ENGLISH_AUSTRALIA:
- case wxLANGUAGE_ENGLISH_NEW_ZEALAND:
- case wxLANGUAGE_ENGLISH_TRINIDAD:
- case wxLANGUAGE_ENGLISH_CARIBBEAN:
- case wxLANGUAGE_ENGLISH_JAMAICA:
- case wxLANGUAGE_ENGLISH_BELIZE:
- case wxLANGUAGE_ENGLISH_EIRE:
- case wxLANGUAGE_ENGLISH_SOUTH_AFRICA:
- case wxLANGUAGE_ENGLISH_ZIMBABWE:
- case wxLANGUAGE_ENGLISH_BOTSWANA:
- case wxLANGUAGE_ENGLISH_DENMARK:
- return wxLANGUAGE_ENGLISH_UK;
-
default:
return language;
}
@@ -391,7 +400,7 @@ void zen::setLanguage(int language) //throw FileError
else
try
{
- zen::setTranslator(new FFSLocale(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, PluralForm::ParsingError
+ zen::setTranslator(new FFSLocale(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, parse_plural::ParsingError
}
catch (lngfile::ParsingError& e)
{
@@ -400,7 +409,7 @@ void zen::setLanguage(int language) //throw FileError
L"%y", numberTo<std::wstring>(e.row + 1)),
L"%z", numberTo<std::wstring>(e.col + 1)));
}
- catch (PluralForm::ParsingError&)
+ catch (parse_plural::ParsingError&)
{
throw FileError(L"Invalid Plural Form");
}
@@ -422,10 +431,3 @@ int zen::retrieveSystemLanguage()
{
return mapLanguageDialect(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));
}
-
-
-const std::vector<ExistingTranslations::Entry>& ExistingTranslations::get()
-{
- static ExistingTranslations instance;
- return instance.locMapping;
-}
diff --git a/lib/lock_holder.h b/lib/lock_holder.h
index dd997853..d4fe27a9 100644
--- a/lib/lock_holder.h
+++ b/lib/lock_holder.h
@@ -46,7 +46,7 @@ public:
try
{
- //lock file creation is synchronous and may block noticably for very slow devices (usb sticks, mapped cloud storages)
+ //lock file creation is synchronous and may block noticeably for very slow devices (usb sticks, mapped cloud storages)
procCallback.forceUiRefresh(); //=> make sure the right folder name is shown on GUI during this time!
lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback)));
}
diff --git a/lib/parse_lng.h b/lib/parse_lng.h
index 92564a1e..b5afe50c 100644
--- a/lib/parse_lng.h
+++ b/lib/parse_lng.h
@@ -51,19 +51,7 @@ void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap
void parseHeader(const std::string& fileStream, TransHeader& header); //throw ParsingError
class TranslationList; //unordered list of unique translation items
-void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream);
-
-
-
-
-
-
-
-
-
-
-
-
+std::string generateLng(const TranslationList& in, const TransHeader& header);
@@ -114,7 +102,7 @@ public:
}
private:
- friend void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream);
+ friend std::string generateLng(const TranslationList& in, const TransHeader& header);
struct Item {virtual ~Item() {} };
struct RegularItem : public Item { RegularItem(const TranslationMap ::value_type& val) : value(val) {} TranslationMap ::value_type value; };
@@ -218,7 +206,11 @@ private:
class Scanner
{
public:
- Scanner(const std::string& fileStream) : stream(fileStream), pos(stream.begin()) {}
+ Scanner(const std::string& fileStream) : stream(fileStream), pos(stream.begin())
+ {
+ if (zen::startsWith(stream, zen::BYTE_ORDER_MARK_UTF8))
+ pos += zen::strLength(zen::BYTE_ORDER_MARK_UTF8);
+ }
Token nextToken()
{
@@ -228,19 +220,19 @@ public:
if (pos == stream.end())
return Token(Token::TK_END);
- for (KnownTokens::TokenMap::const_iterator i = KnownTokens::asList().begin(); i != KnownTokens::asList().end(); ++i)
- if (startsWith(i->second))
+ for (auto it = KnownTokens::asList().begin(); it != KnownTokens::asList().end(); ++it)
+ if (startsWith(it->second))
{
- pos += i->second.size();
- return Token(i->first);
+ pos += it->second.size();
+ return Token(it->first);
}
//rest must be "text"
- std::string::const_iterator textBegin = pos;
+ std::string::const_iterator itBegin = pos;
while (pos != stream.end() && !startsWithKnownTag())
pos = std::find(pos + 1, stream.end(), '<');
- std::string text(textBegin, pos);
+ std::string text(itBegin, pos);
normalize(text); //remove whitespace from end ect.
@@ -255,13 +247,8 @@ public:
size_t posRow() const //current row beginning with 0
{
//count line endings
- size_t crSum = 0; //carriage returns
- size_t nlSum = 0; //new lines
- for (auto it = stream.begin(); it != pos; ++it)
- if (*it == '\r')
- ++crSum;
- else if (*it == '\n')
- ++nlSum;
+ const size_t crSum = std::count(stream.begin(), pos, '\r'); //carriage returns
+ const size_t nlSum = std::count(stream.begin(), pos, '\n'); //new lines
assert(crSum == 0 || nlSum == 0 || crSum == nlSum);
return std::max(crSum, nlSum); //be compatible with Linux/Mac/Win
}
@@ -294,32 +281,15 @@ private:
static void normalize(std::string& text)
{
- //remmove whitespace from end
- while (!text.empty() && zen::isWhiteSpace(*text.rbegin()))
- text.resize(text.size() - 1);
-
- //ensure c-style line breaks
+ zen::trim(text); //remmove whitespace from end
//Delimiter:
//----------
//Linux: 0xA \n
//Mac: 0xD \r
//Win: 0xD 0xA \r\n <- language files are in Windows format
- if (text.find('\r') != std::string::npos)
- {
- std::string tmp;
- for (std::string::const_iterator i = text.begin(); i != text.end(); ++i)
- if (*i == '\r')
- {
- std::string::const_iterator next = i + 1;
- if (next != text.end() && *next == '\n')
- ++i;
- tmp += '\n';
- }
- else
- tmp += *i;
- text = tmp;
- }
+ zen::replace(text, "\r\n", '\n'); //
+ zen::replace(text, "\r", '\n'); //ensure c-style line breaks
}
const std::string stream;
@@ -334,7 +304,6 @@ public:
void parse(TranslationMap& out, TranslationPluralMap& pluralOut, TransHeader& header)
{
- //header
parseHeader(header);
//items
@@ -399,9 +368,7 @@ private:
nextToken();
}
consumeToken(Token::TK_TRG_END);
-
- if (!translation.empty()) //only add if translation is existing
- out.insert(std::make_pair(original, translation));
+ out.insert(std::make_pair(original, translation));
}
void parsePlural(TranslationPluralMap& pluralOut, int formCount)
@@ -437,20 +404,23 @@ private:
throw ParsingError(scn.posRow(), scn.posCol());
consumeToken(Token::TK_TRG_END);
-
- if (!pluralList.empty()) //only add if translation is existing
- pluralOut.insert(std::make_pair(SingularPluralPair(engSingular, engPlural), pluralList));
+ pluralOut.insert(std::make_pair(SingularPluralPair(engSingular, engPlural), pluralList));
}
void nextToken() { tk = scn.nextToken(); }
const Token& token() const { return tk; }
- void consumeToken(Token::Type t)
+ void consumeToken(Token::Type t) //throw ParsingError
+ {
+ expectToken(t); //throw ParsingError
+ nextToken();
+ }
+
+ void expectToken(Token::Type t) //throw ParsingError
{
if (token().type != t)
throw ParsingError(scn.posRow(), scn.posCol());
- nextToken();
}
Scanner scn;
@@ -464,24 +434,22 @@ void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap
out.clear();
pluralOut.clear();
- //skip UTF-8 Byte Ordering Mark
- LngParser prs(zen::startsWith(fileStream, zen::BYTE_ORDER_MARK_UTF8) ? fileStream.substr(3) : fileStream);
- prs.parse(out, pluralOut, header);
+ LngParser(fileStream).parse(out, pluralOut, header);
}
inline
void parseHeader(const std::string& fileStream, TransHeader& header) //throw ParsingError
{
- //skip UTF-8 Byte Ordering Mark
- LngParser prs(zen::startsWith(fileStream, zen::BYTE_ORDER_MARK_UTF8) ? fileStream.substr(3) : fileStream);
- prs.parseHeader(header);
+ LngParser(fileStream).parseHeader(header);
}
inline
void formatMultiLineText(std::string& text)
{
+ assert(!zen::contains(text, "\r\n"));
+
if (text.find('\n') != std::string::npos) //multiple lines
{
if (*text.begin() != '\n')
@@ -492,49 +460,46 @@ void formatMultiLineText(std::string& text)
}
-const std::string LB = "\n";
-const std::string TAB = "\t";
-
-
-void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream)
+std::string generateLng(const TranslationList& in, const TransHeader& header)
{
+ std::string out;
//header
- fileStream += KnownTokens::text(Token::TK_HEADER_BEGIN) + LB;
+ out += KnownTokens::text(Token::TK_HEADER_BEGIN) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_LANG_NAME_BEGIN);
- fileStream += header.languageName;
- fileStream += KnownTokens::text(Token::TK_LANG_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_LANG_NAME_BEGIN);
+ out += header.languageName;
+ out += KnownTokens::text(Token::TK_LANG_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_TRANS_NAME_BEGIN);
- fileStream += header.translatorName;
- fileStream += KnownTokens::text(Token::TK_TRANS_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_TRANS_NAME_BEGIN);
+ out += header.translatorName;
+ out += KnownTokens::text(Token::TK_TRANS_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_LOCALE_NAME_BEGIN);
- fileStream += header.localeName;
- fileStream += KnownTokens::text(Token::TK_LOCALE_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_LOCALE_NAME_BEGIN);
+ out += header.localeName;
+ out += KnownTokens::text(Token::TK_LOCALE_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_FLAG_FILE_BEGIN);
- fileStream += header.flagFile;
- fileStream += KnownTokens::text(Token::TK_FLAG_FILE_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_FLAG_FILE_BEGIN);
+ out += header.flagFile;
+ out += KnownTokens::text(Token::TK_FLAG_FILE_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_PLURAL_COUNT_BEGIN);
- fileStream += zen::numberTo<std::string>(header.pluralCount);
- fileStream += KnownTokens::text(Token::TK_PLURAL_COUNT_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_PLURAL_COUNT_BEGIN);
+ out += zen::numberTo<std::string>(header.pluralCount);
+ out += KnownTokens::text(Token::TK_PLURAL_COUNT_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_PLURAL_DEF_BEGIN);
- fileStream += header.pluralDefinition;
- fileStream += KnownTokens::text(Token::TK_PLURAL_DEF_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_PLURAL_DEF_BEGIN);
+ out += header.pluralDefinition;
+ out += KnownTokens::text(Token::TK_PLURAL_DEF_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_HEADER_END) + LB;
+ out += KnownTokens::text(Token::TK_HEADER_END) + '\n';
- fileStream += LB;
+ out += '\n';
//items
- for (std::vector<TranslationList::Item*>::const_iterator i = in.sequence.begin(); i != in.sequence.end(); ++i)
+ for (auto it = in.sequence.begin(); it != in.sequence.end(); ++it)
{
- const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(*i);
- const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem*>(*i);
+ const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(*it);
+ const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem* >(*it);
if (regular)
{
@@ -544,13 +509,13 @@ void generateLng(const TranslationList& in, const TransHeader& header, std::stri
formatMultiLineText(original);
formatMultiLineText(translation);
- fileStream += KnownTokens::text(Token::TK_SRC_BEGIN);
- fileStream += original;
- fileStream += KnownTokens::text(Token::TK_SRC_END) + LB;
+ out += KnownTokens::text(Token::TK_SRC_BEGIN);
+ out += original;
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_TRG_BEGIN);
- fileStream += translation;
- fileStream += KnownTokens::text(Token::TK_TRG_END) + LB + LB;
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ out += translation;
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
}
else if (plural)
@@ -562,34 +527,36 @@ void generateLng(const TranslationList& in, const TransHeader& header, std::stri
formatMultiLineText(engSingular);
formatMultiLineText(engPlural);
- fileStream += KnownTokens::text(Token::TK_SRC_BEGIN) + LB;
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += engSingular;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += engPlural;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
- fileStream += KnownTokens::text(Token::TK_SRC_END) + LB;
+ out += KnownTokens::text(Token::TK_SRC_BEGIN) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engSingular;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engPlural;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_TRG_BEGIN);
- if (!forms.empty()) fileStream += LB;
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ if (!forms.empty()) out += '\n';
for (PluralForms::const_iterator j = forms.begin(); j != forms.end(); ++j)
{
std::string plForm = *j;
formatMultiLineText(plForm);
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += plForm;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += plForm;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
}
- fileStream += KnownTokens::text(Token::TK_TRG_END) + LB + LB;
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
}
else
{
throw std::logic_error("that's what you get for brittle design ;)");
}
}
+ assert(!zen::contains(out, "\r\n") && !zen::contains(out, "\r"));
+ return zen::replaceCpy(out, '\n', "\r\n"); //back to win line endings
}
}
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index 7af6809e..c3591881 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -7,11 +7,45 @@
#ifndef PARSE_PLURAL_H_INCLUDED
#define PARSE_PLURAL_H_INCLUDED
-#include <list>
#include <memory>
#include <functional>
#include <zen/string_base.h>
+namespace parse_plural
+{
+//expression interface
+struct Expression { virtual ~Expression() {} };
+
+template <class T>
+struct Expr : public Expression
+{
+ typedef T ValueType;
+ virtual ValueType eval() const = 0;
+};
+
+
+class ParsingError {};
+
+class PluralForm
+{
+public:
+ PluralForm(const std::string& stream); //throw ParsingError
+ int getForm(int n) const { n_ = n ; return expr->eval(); }
+
+private:
+ std::shared_ptr<Expr<int>> expr;
+ mutable int n_;
+};
+
+
+
+
+
+
+
+
+//--------------------------- implementation ---------------------------
+
//http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html
//http://translate.sourceforge.net/wiki/l10n/pluralforms
/*
@@ -52,55 +86,57 @@ pm-expression:
variable-number-n-expression
constant-number-expression
( expression )
-*/
-
-//expression interface
-struct Expression { virtual ~Expression() {} };
+.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
+*/
-template <class T>
-struct Expr : public Expression
+namespace implementation
{
- typedef T ValueType;
- virtual ValueType eval() const = 0;
-};
-
//specific binary expression based on STL function objects
template <class StlOp>
struct BinaryExp : public Expr<typename StlOp::result_type>
{
- typedef const Expr<typename StlOp::first_argument_type > ExpLhs;
- typedef const Expr<typename StlOp::second_argument_type> ExpRhs;
+ typedef std::shared_ptr<Expr<typename StlOp::first_argument_type >> ExpLhs;
+ typedef std::shared_ptr<Expr<typename StlOp::second_argument_type>> ExpRhs;
- BinaryExp(const ExpLhs& lhs, const ExpRhs& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) {}
- virtual typename StlOp::result_type eval() const { return biop_(lhs_.eval(), rhs_.eval()); }
- const ExpLhs& lhs_;
- const ExpRhs& rhs_;
+ BinaryExp(const ExpLhs& lhs, const ExpRhs& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) { assert(lhs && rhs); }
+ virtual typename StlOp::result_type eval() const { return biop_(lhs_->eval(), rhs_->eval()); }
+private:
+ ExpLhs lhs_;
+ ExpRhs rhs_;
StlOp biop_;
};
template <class StlOp> inline
-BinaryExp<StlOp> makeBiExp(const Expression& lhs, const Expression& rhs, StlOp biop) //throw std::bad_cast
+std::shared_ptr<BinaryExp<StlOp>> makeBiExp(const std::shared_ptr<Expression>& lhs, const std::shared_ptr<Expression>& rhs, StlOp biop) //throw ParsingError
{
- return BinaryExp<StlOp>(dynamic_cast<const Expr<typename StlOp::first_argument_type >&>(lhs), //throw std::bad_cast
- dynamic_cast<const Expr<typename StlOp::second_argument_type>&>(rhs), biop); //
+ auto exLeft = std::dynamic_pointer_cast<Expr<typename StlOp::first_argument_type >>(lhs);
+ auto exRight = std::dynamic_pointer_cast<Expr<typename StlOp::second_argument_type>>(rhs);
+ if (!exLeft || !exRight)
+ throw ParsingError();
+ return std::make_shared<BinaryExp<StlOp>>(exLeft, exRight, biop);
}
template <class T>
-struct TernaryExp : public Expr<T>
+struct ConditionalExp : public Expr<T>
{
- TernaryExp(const Expr<bool>& ifExp, const Expr<T>& thenExp, const Expr<T>& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) {}
- virtual typename Expr<T>::ValueType eval() const { return ifExp_.eval() ? thenExp_.eval() : elseExp_.eval(); }
- const Expr<bool>& ifExp_;
- const Expr<T>& thenExp_;
- const Expr<T>& elseExp_;
+ ConditionalExp(const std::shared_ptr<Expr<bool>>& ifExp,
+ const std::shared_ptr<Expr<T>>& thenExp,
+ const std::shared_ptr<Expr<T>>& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) { assert(ifExp && thenExp && elseExp); }
+
+ virtual typename Expr<T>::ValueType eval() const { return ifExp_->eval() ? thenExp_->eval() : elseExp_->eval(); }
+private:
+ std::shared_ptr<Expr<bool>> ifExp_;
+ std::shared_ptr<Expr<T>> thenExp_;
+ std::shared_ptr<Expr<T>> elseExp_;
};
struct ConstNumberExp : public Expr<int>
{
ConstNumberExp(int n) : n_(n) {}
virtual int eval() const { return n_; }
+private:
int n_;
};
@@ -108,296 +144,276 @@ struct VariableNumberNExp : public Expr<int>
{
VariableNumberNExp(int& n) : n_(n) {}
virtual int eval() const { return n_; }
+private:
int& n_;
};
+//-------------------------------------------------------------------------------
-class PluralForm
+struct Token
{
-public:
- struct ParsingError {};
-
- //.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
- PluralForm(const std::string& phrase) : n_(0)
+ enum Type
{
- Parser(phrase, //in
- expr, n_, dump); //out
- }
+ TK_TERNARY_QUEST,
+ TK_TERNARY_COLON,
+ TK_OR,
+ TK_AND,
+ TK_EQUAL,
+ TK_NOT_EQUAL,
+ TK_LESS,
+ TK_LESS_EQUAL,
+ TK_GREATER,
+ TK_GREATER_EQUAL,
+ TK_MODULUS,
+ TK_VARIABLE_N,
+ TK_CONST_NUMBER,
+ TK_BRACKET_LEFT,
+ TK_BRACKET_RIGHT,
+ TK_END
+ };
- int getForm(int n) const { n_ = n ; return expr->eval(); }
+ Token(Type t) : type(t), number(0) {}
+ Token(int num) : type(TK_CONST_NUMBER), number(num) {}
-private:
- typedef std::list<std::shared_ptr<Expression> > DumpList;
+ Type type;
+ int number; //if type == TK_CONST_NUMBER
+};
- struct Token
+class Scanner
+{
+public:
+ Scanner(const std::string& stream) : stream_(stream), pos(stream_.begin())
{
- enum Type
- {
- TK_TERNARY_QUEST,
- TK_TERNARY_COLON,
- TK_OR,
- TK_AND,
- TK_EQUAL,
- TK_NOT_EQUAL,
- TK_LESS,
- TK_LESS_EQUAL,
- TK_GREATER,
- TK_GREATER_EQUAL,
- TK_MODULUS,
- TK_VARIABLE_N,
- TK_CONST_NUMBER,
- TK_BRACKET_LEFT,
- TK_BRACKET_RIGHT,
- TK_END
- };
-
- Token(Type t) : type(t), number(0) {}
- Token(int num) : type(TK_CONST_NUMBER), number(num) {}
-
- Type type;
- int number; //if type == TK_CONST_NUMBER
- };
+ tokens.push_back(std::make_pair("?" , Token::TK_TERNARY_QUEST));
+ tokens.push_back(std::make_pair(":" , Token::TK_TERNARY_COLON));
+ tokens.push_back(std::make_pair("||", Token::TK_OR ));
+ tokens.push_back(std::make_pair("&&", Token::TK_AND ));
+ tokens.push_back(std::make_pair("==", Token::TK_EQUAL ));
+ tokens.push_back(std::make_pair("!=", Token::TK_NOT_EQUAL ));
+ tokens.push_back(std::make_pair("<=", Token::TK_LESS_EQUAL ));
+ tokens.push_back(std::make_pair("<" , Token::TK_LESS ));
+ tokens.push_back(std::make_pair(">=", Token::TK_GREATER_EQUAL));
+ tokens.push_back(std::make_pair(">" , Token::TK_GREATER ));
+ tokens.push_back(std::make_pair("%" , Token::TK_MODULUS ));
+ tokens.push_back(std::make_pair("n" , Token::TK_VARIABLE_N ));
+ tokens.push_back(std::make_pair("N" , Token::TK_VARIABLE_N ));
+ tokens.push_back(std::make_pair("(" , Token::TK_BRACKET_LEFT ));
+ tokens.push_back(std::make_pair(")" , Token::TK_BRACKET_RIGHT));
+ }
- class Scanner
+ Token nextToken()
{
- public:
- Scanner(const std::string& phrase) : stream(phrase), pos(stream.begin())
- {
- tokens.push_back(std::make_pair("?" , Token::TK_TERNARY_QUEST));
- tokens.push_back(std::make_pair(":" , Token::TK_TERNARY_COLON));
- tokens.push_back(std::make_pair("||", Token::TK_OR ));
- tokens.push_back(std::make_pair("&&", Token::TK_AND ));
- tokens.push_back(std::make_pair("==", Token::TK_EQUAL ));
- tokens.push_back(std::make_pair("!=", Token::TK_NOT_EQUAL ));
- tokens.push_back(std::make_pair("<=", Token::TK_LESS_EQUAL ));
- tokens.push_back(std::make_pair("<" , Token::TK_LESS ));
- tokens.push_back(std::make_pair(">=", Token::TK_GREATER_EQUAL));
- tokens.push_back(std::make_pair(">" , Token::TK_GREATER ));
- tokens.push_back(std::make_pair("%" , Token::TK_MODULUS ));
- tokens.push_back(std::make_pair("n" , Token::TK_VARIABLE_N ));
- tokens.push_back(std::make_pair("N" , Token::TK_VARIABLE_N ));
- tokens.push_back(std::make_pair("(" , Token::TK_BRACKET_LEFT ));
- tokens.push_back(std::make_pair(")" , Token::TK_BRACKET_RIGHT));
- }
-
- Token nextToken()
- {
- //skip whitespace
- pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
+ //skip whitespace
+ pos = std::find_if(pos, stream_.end(), [](char c) { return !zen::isWhiteSpace(c); });
- if (pos == stream.end())
- return Token::TK_END;
+ if (pos == stream_.end())
+ return Token::TK_END;
- for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
- if (startsWith(iter->first))
- {
- pos += iter->first.size();
- return Token(iter->second);
- }
-
- auto digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
-
- if (digitEnd != pos)
+ for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
+ if (startsWith(iter->first))
{
- int number = zen::stringTo<int>(std::string(&*pos, digitEnd - pos));
- pos = digitEnd;
- return number;
+ pos += iter->first.size();
+ return Token(iter->second);
}
- throw ParsingError(); //unknown token
- }
+ auto digitEnd = std::find_if(pos, stream_.end(), [](char c) { return !zen::isDigit(c); });
- private:
- bool startsWith(const std::string& prefix) const
+ if (digitEnd != pos)
{
- if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
- return false;
- return std::equal(prefix.begin(), prefix.end(), pos);
+ int number = zen::stringTo<int>(std::string(pos, digitEnd));
+ pos = digitEnd;
+ return number;
}
- typedef std::vector<std::pair<std::string, Token::Type> > TokenList;
- TokenList tokens;
+ throw ParsingError(); //unknown token
+ }
- const std::string stream;
- std::string::const_iterator pos;
- };
+private:
+ bool startsWith(const std::string& prefix) const
+ {
+ if (stream_.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
+ return false;
+ return std::equal(prefix.begin(), prefix.end(), pos);
+ }
+ typedef std::vector<std::pair<std::string, Token::Type> > TokenList;
+ TokenList tokens;
+
+ const std::string stream_;
+ std::string::const_iterator pos;
+};
+
+//-------------------------------------------------------------------------------
+
+class Parser
+{
+public:
+ Parser(const std::string& stream, int& n) :
+ scn(stream),
+ tk(scn.nextToken()),
+ n_(n) {}
- class Parser
+ std::shared_ptr<Expr<int>> parse() //throw ParsingError; return value always bound!
{
- public:
- Parser(const std::string& phrase, //in
- const Expr<int>*& expr, int& n, PluralForm::DumpList& dump) : //out
- scn(phrase),
- tk(scn.nextToken()),
- n_(n),
- dump_(dump)
- {
- try
- {
- const Expression& e = parse(); //throw std::bad_cast, ParsingError
- expr = &dynamic_cast<const Expr<int>&>(e); //
- }
- catch (std::bad_cast&) { throw ParsingError(); }
+ auto e = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //throw ParsingError
+ if (!e)
+ throw ParsingError();
+ expectToken(Token::TK_END);
+ return e;
+ }
- consumeToken(Token::TK_END);
- }
+private:
+ std::shared_ptr<Expression> parseExpression() { return parseConditional(); }//throw ParsingError
- private:
- void nextToken() { tk = scn.nextToken(); }
- const Token& token() const { return tk; }
+ std::shared_ptr<Expression> parseConditional() //throw ParsingError
+ {
+ std::shared_ptr<Expression> e = parseLogicalOr();
- void consumeToken(Token::Type t) //throw ParsingError
+ if (token().type == Token::TK_TERNARY_QUEST)
{
- if (token().type != t)
- throw ParsingError();
nextToken();
- }
- const Expression& parse() { return parseConditional(); }; //throw std::bad_cast, ParsingError
+ auto ifExp = std::dynamic_pointer_cast<Expr<bool>>(e);
+ auto thenExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //associativity: <-
- const Expression& parseConditional()
- {
- const Expression& e = parseLogicalOr();
+ expectToken(Token::TK_TERNARY_COLON);
+ nextToken();
- if (token().type == Token::TK_TERNARY_QUEST)
- {
- nextToken();
- const Expression& thenEx = parse(); //associativity: <-
- consumeToken(Token::TK_TERNARY_COLON);
- const Expression& elseEx = parse(); //
-
- return manageObj(TernaryExp<int>(dynamic_cast<const Expr<bool>&>(e), //
- dynamic_cast<const Expr<int>&>(thenEx), //throw std::bad_cast
- dynamic_cast<const Expr<int>&>(elseEx))); //
- }
- return e;
+ auto elseExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //
+ if (!ifExp || !thenExp || !elseExp)
+ throw ParsingError();
+ return std::make_shared<ConditionalExp<int>>(ifExp, thenExp, elseExp);
}
+ return e;
+ }
- const Expression& parseLogicalOr()
+ std::shared_ptr<Expression> parseLogicalOr()
+ {
+ std::shared_ptr<Expression> e = parseLogicalAnd();
+ while (token().type == Token::TK_OR) //associativity: ->
{
- const Expression* e = &parseLogicalAnd();
- while (token().type == Token::TK_OR) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parseLogicalAnd();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_or<bool>())); //throw std::bad_cast
- }
- return *e;
+ nextToken();
+
+ std::shared_ptr<Expression> rhs = parseLogicalAnd();
+ e = makeBiExp(e, rhs, std::logical_or<bool>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parseLogicalAnd()
+ std::shared_ptr<Expression> parseLogicalAnd()
+ {
+ std::shared_ptr<Expression> e = parseEquality();
+ while (token().type == Token::TK_AND) //associativity: ->
{
- const Expression* e = &parseEquality();
- while (token().type == Token::TK_AND) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parseEquality();
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseEquality();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_and<bool>())); //throw std::bad_cast
- }
- return *e;
+ e = makeBiExp(e, rhs, std::logical_and<bool>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parseEquality()
- {
- const Expression& e = parseRelational();
+ std::shared_ptr<Expression> parseEquality()
+ {
+ std::shared_ptr<Expression> e = parseRelational();
- Token::Type t = token().type;
- if (t == Token::TK_EQUAL || t == Token::TK_NOT_EQUAL) //associativity: n/a
- {
- nextToken();
- const Expression& rhs = parseRelational();
+ Token::Type t = token().type;
+ if (t == Token::TK_EQUAL || //associativity: n/a
+ t == Token::TK_NOT_EQUAL)
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseRelational();
- if (t == Token::TK_EQUAL) return manageObj(makeBiExp(e, rhs, std::equal_to <int>())); //throw std::bad_cast
- if (t == Token::TK_NOT_EQUAL) return manageObj(makeBiExp(e, rhs, std::not_equal_to<int>())); //
- }
- return e;
+ if (t == Token::TK_EQUAL) return makeBiExp(e, rhs, std::equal_to <int>()); //throw ParsingError
+ if (t == Token::TK_NOT_EQUAL) return makeBiExp(e, rhs, std::not_equal_to<int>()); //
}
+ return e;
+ }
- const Expression& parseRelational()
- {
- const Expression& e = parseMultiplicative();
+ std::shared_ptr<Expression> parseRelational()
+ {
+ std::shared_ptr<Expression> e = parseMultiplicative();
- Token::Type t = token().type;
- if (t == Token::TK_LESS || //associativity: n/a
- t == Token::TK_LESS_EQUAL ||
- t == Token::TK_GREATER ||
- t == Token::TK_GREATER_EQUAL)
- {
- nextToken();
- const Expression& rhs = parseMultiplicative();
+ Token::Type t = token().type;
+ if (t == Token::TK_LESS || //associativity: n/a
+ t == Token::TK_LESS_EQUAL ||
+ t == Token::TK_GREATER ||
+ t == Token::TK_GREATER_EQUAL)
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseMultiplicative();
- if (t == Token::TK_LESS) return manageObj(makeBiExp(e, rhs, std::less <int>())); //
- if (t == Token::TK_LESS_EQUAL) return manageObj(makeBiExp(e, rhs, std::less_equal <int>())); //throw std::bad_cast
- if (t == Token::TK_GREATER) return manageObj(makeBiExp(e, rhs, std::greater <int>())); //
- if (t == Token::TK_GREATER_EQUAL) return manageObj(makeBiExp(e, rhs, std::greater_equal<int>())); //
- }
- return e;
+ if (t == Token::TK_LESS) return makeBiExp(e, rhs, std::less <int>()); //
+ if (t == Token::TK_LESS_EQUAL) return makeBiExp(e, rhs, std::less_equal <int>()); //throw ParsingError
+ if (t == Token::TK_GREATER) return makeBiExp(e, rhs, std::greater <int>()); //
+ if (t == Token::TK_GREATER_EQUAL) return makeBiExp(e, rhs, std::greater_equal<int>()); //
}
+ return e;
+ }
- const Expression& parseMultiplicative()
- {
- const Expression* e = &parsePrimary();
+ std::shared_ptr<Expression> parseMultiplicative()
+ {
+ std::shared_ptr<Expression> e = parsePrimary();
- while (token().type == Token::TK_MODULUS) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parsePrimary();
+ while (token().type == Token::TK_MODULUS) //associativity: ->
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parsePrimary();
- //"compile-time" check: n % 0
- if (auto literal = dynamic_cast<const ConstNumberExp*>(&rhs))
- if (literal->eval() == 0)
- throw ParsingError();
+ //"compile-time" check: n % 0
+ if (auto literal = std::dynamic_pointer_cast<ConstNumberExp>(rhs))
+ if (literal->eval() == 0)
+ throw ParsingError();
- e = &manageObj(makeBiExp(*e, rhs, std::modulus<int>())); //throw std::bad_cast
- }
- return *e;
+ e = makeBiExp(e, rhs, std::modulus<int>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parsePrimary()
+ std::shared_ptr<Expression> parsePrimary()
+ {
+ if (token().type == Token::TK_VARIABLE_N)
{
- if (token().type == Token::TK_VARIABLE_N)
- {
- nextToken();
- return manageObj(VariableNumberNExp(n_));
- }
- else if (token().type == Token::TK_CONST_NUMBER)
- {
- const int number = token().number;
- nextToken();
- return manageObj(ConstNumberExp(number));
- }
- else if (token().type == Token::TK_BRACKET_LEFT)
- {
- nextToken();
- const Expression& e = parse();
-
- consumeToken(Token::TK_BRACKET_RIGHT);
- return e;
- }
- else
- throw ParsingError();
+ nextToken();
+ return std::make_shared<VariableNumberNExp>(n_);
}
-
- template <class T>
- const T& manageObj(const T& obj)
+ else if (token().type == Token::TK_CONST_NUMBER)
{
- dump_.push_back(std::make_shared<T>(obj));
- return static_cast<T&>(*dump_.back());
+ const int number = token().number;
+ nextToken();
+ return std::make_shared<ConstNumberExp>(number);
}
+ else if (token().type == Token::TK_BRACKET_LEFT)
+ {
+ nextToken();
+ std::shared_ptr<Expression> e = parseExpression();
- Scanner scn;
- Token tk;
+ expectToken(Token::TK_BRACKET_RIGHT);
+ nextToken();
+ return e;
+ }
+ else
+ throw ParsingError();
+ }
- int& n_;
- DumpList& dump_; //manage polymorphc object lifetimes
- };
+ void nextToken() { tk = scn.nextToken(); }
+ const Token& token() const { return tk; }
- const Expr<int>* expr;
- mutable int n_;
+ void expectToken(Token::Type t) //throw ParsingError
+ {
+ if (token().type != t)
+ throw ParsingError();
+ }
- PluralForm::DumpList dump; //manage polymorphc object lifetimes
+ Scanner scn;
+ Token tk;
+ int& n_;
};
+}
+
+
+inline
+PluralForm::PluralForm(const std::string& stream) : expr(implementation::Parser(stream, n_).parse()) {} //throw ParsingError
+}
-#endif // PARSE_PLURAL_H_INCLUDED
+#endif // PARSE_PLURAL_H_INCLUDED \ No newline at end of file
diff --git a/lib/perf_check.cpp b/lib/perf_check.cpp
index c6a4e2d1..85a98910 100644
--- a/lib/perf_check.cpp
+++ b/lib/perf_check.cpp
@@ -98,34 +98,13 @@ wxString PerfCheck::getBytesPerSecond() const
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
+ if (!numeric::isNull(timeDelta) && dataDelta > 0)
return filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
}
return L"-"; //fallback
}
-wxString PerfCheck::getOverallBytesPerSecond() const //for all samples
-{
- warn_static("WTF!? tihs considers window only!")
-
- 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_;
-
- if (!numeric::isNull(timeDelta))
- if (dataDelta > 0) //may be negative if user cancels copying
- return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
- }
- return L"-"; //fallback
-}
-
-
/*
class for calculation of remaining time:
----------------------------------------
diff --git a/lib/perf_check.h b/lib/perf_check.h
index b60c31c9..f314f842 100644
--- a/lib/perf_check.h
+++ b/lib/perf_check.h
@@ -21,7 +21,6 @@ public:
wxString getRemainingTime(double dataRemaining) const;
wxString getBytesPerSecond() const; //for window
- wxString getOverallBytesPerSecond() const; //for all samples
private:
const long windowSizeRemTime; //unit: [ms]
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index a11f841c..e38749f9 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -75,7 +75,7 @@ void setXmlType(XmlDoc& doc, XmlType type) //throw()
wxString xmlAccess::getGlobalConfigFile()
{
- return toWx(zen::getConfigDir()) + wxT("GlobalSettings.xml");
+ return toWx(zen::getConfigDir()) + L"GlobalSettings.xml";
}
@@ -761,6 +761,64 @@ void writeStruc(const ColumnAttributeNavi& value, XmlElement& output)
out.attribute("Width", value.offset_);
out.attribute("Stretch", value.stretch_);
}
+
+
+template <> inline
+bool readStruc(const XmlElement& input, ViewFilterDefault& value)
+{
+ XmlIn in(input);
+
+ bool success = true;
+ auto readAttr = [&](XmlIn& elemIn, const char name[], bool& v)
+ {
+ if (!elemIn.attribute(name, v))
+ success = false;
+ };
+
+ XmlIn catView = in["CategoryView"];
+ readAttr(catView, "LeftOnly" , value.leftOnly);
+ readAttr(catView, "RightOnly" , value.rightOnly);
+ readAttr(catView, "LeftNewer" , value.leftNewer);
+ readAttr(catView, "RightNewer", value.rightNewer);
+ readAttr(catView, "Different" , value.different);
+ readAttr(catView, "Equal" , value.equal);
+ readAttr(catView, "Conflict" , value.conflict);
+
+ XmlIn actView = in["ActionView"];
+ readAttr(actView, "CreateLeft" , value.createLeft);
+ readAttr(actView, "CreateRight", value.createRight);
+ readAttr(actView, "UpdateLeft" , value.updateLeft);
+ readAttr(actView, "UpdateRight", value.updateRight);
+ readAttr(actView, "DeleteLeft" , value.deleteLeft);
+ readAttr(actView, "DeleteRight", value.deleteRight);
+ readAttr(actView, "DoNothing" , value.doNothing);
+
+ return success; //[!] avoid short-circuit evaluation above
+}
+
+template <> inline
+void writeStruc(const ViewFilterDefault& value, XmlElement& output)
+{
+ XmlOut out(output);
+
+ XmlOut catView = out["CategoryView"];
+ catView.attribute("LeftOnly" , value.leftOnly);
+ catView.attribute("RightOnly" , value.rightOnly);
+ catView.attribute("LeftNewer" , value.leftNewer);
+ catView.attribute("RightNewer", value.rightNewer);
+ catView.attribute("Different" , value.different);
+ catView.attribute("Equal" , value.equal);
+ catView.attribute("Conflict" , value.conflict);
+
+ XmlOut actView = out["ActionView"];
+ actView.attribute("CreateLeft" , value.createLeft);
+ actView.attribute("CreateRight", value.createRight);
+ actView.attribute("UpdateLeft" , value.updateLeft);
+ actView.attribute("UpdateRight", value.updateRight);
+ actView.attribute("DeleteLeft" , value.deleteLeft);
+ actView.attribute("DeleteRight", value.deleteRight);
+ actView.attribute("DoNothing" , value.doNothing);
+}
}
@@ -798,8 +856,12 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg)
in["CustomDeletionFolder"](syncCfg.versioningDirectory);//obsolete name
else
in["VersioningFolder"](syncCfg.versioningDirectory);
+
warn_static("remove after migration?")
- if (in["VersioningStyle"]) //new parameter
+ if (in["VersioningFolder"] &&
+ in["VersioningFolder"].get()->getAttribute("Style", syncCfg.versioningStyle)) //new parameter, do not complain when missing
+ ;
+ else if (in["VersioningStyle"]) //obsolete name
in["VersioningStyle"](syncCfg.versioningStyle);
else
syncCfg.versioningStyle = VER_STYLE_ADD_TIMESTAMP; //obsolete fallback
@@ -921,7 +983,16 @@ void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
inGuiCfg["HideExcluded"](config.hideExcludedItems);
inGuiCfg["HandleError" ](config.handleError);
- inGuiCfg["SyncPreviewActive"](config.showSyncAction);
+
+ warn_static("remove after migration?")
+ if (inGuiCfg["SyncPreviewActive"]) //obsolete name
+ inGuiCfg["SyncPreviewActive"](config.showSyncAction);
+ else
+ {
+ std::string val;
+ if (inGuiCfg["MiddleGridView"](val)) //refactor into enum!?
+ config.showSyncAction = val == "Action";
+ }
}
@@ -1003,7 +1074,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inWnd.attribute("Maximized", config.gui.isMaximized);
XmlIn inManualDel = inWnd["ManualDeletion"];
- inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ //inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
inManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
inWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
@@ -1031,7 +1102,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inColRight(config.gui.columnAttribRight);
//###########################################################
- inWnd["Layout"](config.gui.guiPerspectiveLast);
+ inWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
+ inWnd["Layout" ](config.gui.guiPerspectiveLast);
//load config file history
warn_static("remove after migration?")
@@ -1140,7 +1212,7 @@ void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
out["DeletionPolicy" ](syncCfg.handleDeletion);
out["VersioningFolder"](syncCfg.versioningDirectory);
//out["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit);
- out["VersioningStyle"](syncCfg.versioningStyle);
+ out["VersioningFolder"].attribute("Style", syncCfg.versioningStyle);
}
@@ -1234,9 +1306,9 @@ void writeConfig(const XmlGuiConfig& config, XmlOut& out)
//write GUI specific config data
XmlOut outGuiCfg = out["GuiConfig"];
- outGuiCfg["HideExcluded" ](config.hideExcludedItems);
- outGuiCfg["HandleError" ](config.handleError);
- outGuiCfg["SyncPreviewActive"](config.showSyncAction);
+ outGuiCfg["HideExcluded" ](config.hideExcludedItems);
+ outGuiCfg["HandleError" ](config.handleError);
+ outGuiCfg["MiddleGridView"](config.showSyncAction ? "Action" : "Category"); //refactor into enum!?
}
void writeConfig(const XmlBatchConfig& config, XmlOut& out)
@@ -1296,7 +1368,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outWnd.attribute("Maximized", config.gui.isMaximized);
XmlOut outManualDel = outWnd["ManualDeletion"];
- outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ //outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
outManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
outWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
@@ -1323,7 +1395,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outColRight(config.gui.columnAttribRight);
//###########################################################
- outWnd["Layout"](config.gui.guiPerspectiveLast);
+ outWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
+ outWnd["Layout" ](config.gui.guiPerspectiveLast);
//load config file history
outGui["LastUsedConfig"](config.gui.lastUsedConfigFiles);
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 29237081..d0396d6e 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -112,6 +112,18 @@ enum FileIconSize
};
+struct ViewFilterDefault
+{
+ ViewFilterDefault() : equal(false)
+ {
+ leftOnly = rightOnly = leftNewer = rightNewer = different = conflict = true;
+ createLeft = createRight = updateLeft = updateRight = deleteLeft = deleteRight = doNothing = true;
+ }
+ bool equal;
+ bool leftOnly, rightOnly, leftNewer, rightNewer, different, conflict; //category view
+ bool createLeft, createRight, updateLeft, updateRight, deleteLeft, deleteRight, doNothing; //action view
+};
+
wxString getGlobalConfigFile();
struct XmlGlobalSettings
@@ -161,7 +173,7 @@ struct XmlGlobalSettings
cfgFileHistMax(30),
folderHistMax(15),
onCompletionHistoryMax(8),
- deleteOnBothSides(false),
+ //deleteOnBothSides(false),
useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message
#ifdef FFS_WIN
textSearchRespectCase(false),
@@ -216,7 +228,7 @@ struct XmlGlobalSettings
std::vector<std::wstring> onCompletionHistory;
size_t onCompletionHistoryMax;
- bool deleteOnBothSides;
+ //bool deleteOnBothSides;
bool useRecyclerForManualDeletion;
bool textSearchRespectCase;
@@ -225,6 +237,7 @@ struct XmlGlobalSettings
long lastUpdateCheck; //time of last update check
+ ViewFilterDefault viewFilterDefault;
wxString guiPerspectiveLast; //used by wxAuiManager
} gui;
diff --git a/lib/resources.cpp b/lib/resources.cpp
index 7d46739e..2f7daeaf 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -87,8 +87,8 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& imageName) const
{
auto it = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified
- imageName + L".png" :
- imageName);
+ imageName + L".png" :
+ imageName);
if (it != bitmaps.end())
return it->second;
else
diff --git a/lib/status_handler.cpp b/lib/status_handler.cpp
index c24c6f50..fd3b2d96 100644
--- a/lib/status_handler.cpp
+++ b/lib/status_handler.cpp
@@ -22,7 +22,7 @@ void zen::updateUiNow()
namespace
{
-const std::int64_t TICKS_UPDATE_INTERVAL = UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
+const std::int64_t TICKS_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * ticksPerSec() / 1000;
TickVal lastExec = getTicks();
};
diff --git a/lib/status_handler.h b/lib/status_handler.h
index 93f9892c..ed496824 100644
--- a/lib/status_handler.h
+++ b/lib/status_handler.h
@@ -67,7 +67,7 @@ protected:
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 updateProcessedData(int objectsDelta, Int64 dataDelta) { updateData(numbersCurrent_, objectsDelta, dataDelta); } //note: these methods MUST 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()
diff --git a/lib/versioning.cpp b/lib/versioning.cpp
index d4b6e2b2..a72433cc 100644
--- a/lib/versioning.cpp
+++ b/lib/versioning.cpp
@@ -226,8 +226,26 @@ private:
}
-void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
+bool FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
{
+ struct CallbackMoveFileImpl : public CallbackMoveDir
+ {
+ CallbackMoveFileImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ private:
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) {}
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) {}
+ virtual void updateStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
+ CallbackMoveFile& callback_;
+ } cb(callback);
+
+ return revisionFileImpl(sourceFile, relativeName, cb); //throw FileError
+}
+
+
+bool FileVersioner::revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+{
+ bool moveSuccessful = false;
+
moveItemToVersioning(sourceFile, //throw FileError
relativeName,
versioningDirectory_,
@@ -235,26 +253,38 @@ void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relat
versioningStyle_,
[&](const Zstring& source, const Zstring& target)
{
+ callback.onBeforeFileMove(source, target); //if we're called by revisionDirImpl() we know that "source" exists!
+ //when called by revisionFile(), "source" might not exist, however onBeforeFileMove() is not propagated in this case!
+
struct CopyCallbackImpl : public CallbackCopyFile
{
- CopyCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ CopyCallbackImpl(CallbackMoveDir& callback) : callback_(callback) {}
private:
virtual void deleteTargetFile(const Zstring& targetFile) { assert(!somethingExists(targetFile)); }
virtual void updateCopyStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
- CallbackMoveFile& callback_;
+ CallbackMoveDir& callback_;
} copyCallback(callback);
- callback.onBeforeFileMove(source, target);
moveFile(source, target, copyCallback); //throw FileError
- callback.objectProcessed();
+ moveSuccessful = true;
});
+ return moveSuccessful;
+}
+
- //fileRelNames.push_back(relativeName);
+void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+{
+ //no error situation if directory is not existing! manual deletion relies on it!
+ if (!somethingExists(sourceDir))
+ return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ revisionDirImpl(sourceDir, relativeName, callback); //throw FileError
}
-void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
+void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
{
+ assert(somethingExists(sourceDir)); //[!]
+
//create target
if (symlinkExists(sourceDir)) //on Linux there is just one type of symlinks, and since we do revision file symlinks, we should revision dir symlinks as well!
{
@@ -267,10 +297,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
{
callback.onBeforeDirMove(source, target);
moveDirSymlink(source, target); //throw FileError
- callback.objectProcessed();
});
-
- //fileRelNames.push_back(relativeName);
}
else
{
@@ -278,24 +305,15 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
assert(endsWith(sourceDir, relativeName)); //usually, yes, but we might relax this in the future
const Zstring targetDir = appendSeparator(versioningDirectory_) + relativeName;
- callback.onBeforeDirMove(sourceDir, targetDir);
-
//makeDirectory(targetDir); //FileError -> create only when needed in moveFileToVersioning(); avoids empty directories
//traverse source directory one level
std::vector<Zstring> fileList; //list of *short* names
std::vector<Zstring> dirList; //
- try
{
TraverseFilesOneLevel tol(fileList, dirList); //throw FileError
traverseFolder(sourceDir, tol); //
}
- catch (FileError&)
- {
- if (!somethingExists(sourceDir)) //no source at all is not an error (however a file as source when a directory is expected, *is* an error!)
- return; //object *not* processed
- throw;
- }
const Zstring sourceDirPf = appendSeparator(sourceDir);
const Zstring relnamePf = appendSeparator(relativeName);
@@ -304,33 +322,23 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
std::for_each(fileList.begin(), fileList.end(),
[&](const Zstring& shortname)
{
- revisionFile(sourceDirPf + shortname, //throw FileError
- relnamePf + shortname,
- callback);
+ revisionFileImpl(sourceDirPf + shortname, //throw FileError
+ relnamePf + shortname,
+ callback);
});
//move items in subdirectories
std::for_each(dirList.begin(), dirList.end(),
[&](const Zstring& shortname)
{
- revisionDir(sourceDirPf + shortname, //throw FileError
- relnamePf + shortname,
- callback);
+ revisionDirImpl(sourceDirPf + shortname, //throw FileError
+ relnamePf + shortname,
+ callback);
});
//delete source
- struct RemoveCallbackImpl : public CallbackRemoveDir
- {
- RemoveCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
- private:
- virtual void notifyFileDeletion(const Zstring& filename) { callback_.updateStatus(0); }
- virtual void notifyDirDeletion (const Zstring& dirname ) { callback_.updateStatus(0); }
- CallbackMoveFile& callback_;
- } removeCallback(callback);
-
- removeDirectory(sourceDir, &removeCallback); //throw FileError
-
- callback.objectProcessed();
+ callback.onBeforeDirMove(sourceDir, targetDir);
+ removeDirectory(sourceDir); //throw FileError
}
}
diff --git a/lib/versioning.h b/lib/versioning.h
index 3e0dd33c..faa96359 100644
--- a/lib/versioning.h
+++ b/lib/versioning.h
@@ -17,6 +17,7 @@
namespace zen
{
+struct CallbackMoveDir;
struct CallbackMoveFile;
//e.g. move C:\Source\subdir\Sample.txt -> D:\Revisions\subdir\Sample.txt 2012-05-15 131513.txt
@@ -42,15 +43,18 @@ public:
timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)) //e.g. "2012-05-15 131513"
{
if (timeStamp_.size() != 17) //formatTime() returns empty string on error; unexpected length: e.g. problem in year 10000!
- throw FileError(_("Failure to create time stamp for versioning:") + L" \'" + timeStamp_ + L"\'");
+ throw FileError(_("Failure to create timestamp for versioning:") + L" \'" + timeStamp_ + L"\'");
}
- void revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
- void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
+ bool revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing
+ void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
//void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
private:
+ bool revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+ void revisionDirImpl (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+
const VersioningStyle versioningStyle_;
const Zstring versioningDirectory_;
const Zstring timeStamp_;
@@ -59,22 +63,20 @@ private:
};
-struct CallbackMoveFile
+struct CallbackMoveFile //see CallbackCopyFile for limitations when throwing exceptions!
{
- virtual ~CallbackMoveFile() {} //see CallbackCopyFile for limitations when throwing exceptions!
-
- virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call before each (planned) move
- virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; //
- virtual void objectProcessed() = 0; //one call after each completed move (count objects total)
-
- //called frequently if move has to revert to copy + delete:
- virtual void updateStatus(Int64 bytesDelta) = 0;
+ virtual ~CallbackMoveFile() {}
+ virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
};
+struct CallbackMoveDir //see CallbackCopyFile for limitations when throwing exceptions!
+{
+ virtual ~CallbackMoveDir() {}
-
-
-
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call for each *existing* object!
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; //
+ virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
+};
diff --git a/process_callback.h b/process_callback.h
index 0f540df6..036ad79a 100644
--- a/process_callback.h
+++ b/process_callback.h
@@ -34,16 +34,20 @@ struct ProcessCallback
//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!
- virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta) = 0; //throw()!!
+ virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta) = 0; //noexcept!!
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 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)
- 7. Copy sparse files */
+ /*the estimated and actual total workload may change *during* sync:
+ 1. detected file can be moved -> fallback to copy + delete
+ 2. file copy, actual size changed after comparison
+ 3. file contains significant ADS data, is sparse or compressed
+ 4. auto-resolution for failed create operations due to missing source
+ 5. directory deletion: may contain more items than scanned by FFS (excluded by filter) or less (contains followed symlinks)
+ 6. delete directory to recycler: no matter how many child-elements exist, this is only 1 item to process!
+ 7. file/directory already deleted externally: nothing to do, 0 logical operations and data
+ 8. user-defined deletion directory on different volume: full file copy required (instead of move)
+ 9. Binary file comparison: if files differ at the first few bytes, the result is already known
+ 10. Error during file copy, retry: bytes were copied => increases total workload!
+ */
//opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
virtual void requestUiRefresh() = 0; //throw ?
diff --git a/synchronization.cpp b/synchronization.cpp
index 38a6e32c..b3eaf4e4 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -6,6 +6,7 @@
#include "synchronization.h"
#include <memory>
+#include <random>
#include <deque>
#include <stdexcept>
#include <wx/file.h> //get rid!?
@@ -43,7 +44,6 @@ int getCUD(const SyncStatistics& stat)
}
}
-
void SyncStatistics::init()
{
createLeft = 0;
@@ -52,7 +52,6 @@ void SyncStatistics::init()
updateRight = 0;
deleteLeft = 0;
deleteRight = 0;
- //conflict = 0;
rowsTotal = 0;
}
@@ -138,8 +137,6 @@ void SyncStatistics::calcStats(const FileMapping& fileObj)
break;
case SO_UNRESOLVED_CONFLICT:
- //++conflict;
- //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
conflictMsgs.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
break;
@@ -190,8 +187,6 @@ void SyncStatistics::calcStats(const SymLinkMapping& linkObj)
break;
case SO_UNRESOLVED_CONFLICT:
- //++conflict;
- //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
conflictMsgs.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict()));
break;
@@ -228,14 +223,7 @@ void SyncStatistics::calcStats(const DirMapping& dirObj)
++deleteRight;
break;
- case SO_OVERWRITE_LEFT:
- case SO_OVERWRITE_RIGHT:
- assert(false);
- break;
-
case SO_UNRESOLVED_CONFLICT:
- //++conflict;
- //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
conflictMsgs.push_back(std::make_pair(dirObj.getObjRelativeName(), dirObj.getSyncOpConflict()));
break;
@@ -247,6 +235,8 @@ void SyncStatistics::calcStats(const DirMapping& dirObj)
++updateRight;
break;
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
case SO_MOVE_LEFT_SOURCE:
case SO_MOVE_RIGHT_SOURCE:
case SO_MOVE_LEFT_TARGET:
@@ -274,9 +264,9 @@ std::vector<zen::FolderPairSyncCfg> zen::extractSyncCfg(const MainConfiguration&
std::vector<FolderPairSyncCfg> output;
//process all pairs
- for (auto i = allPairs.begin(); i != allPairs.end(); ++i)
+ for (auto it = allPairs.begin(); it != allPairs.end(); ++it)
{
- SyncConfig syncCfg = i->altSyncConfig.get() ? *i->altSyncConfig : mainCfg.syncCfg;
+ SyncConfig syncCfg = it->altSyncConfig.get() ? *it->altSyncConfig : mainCfg.syncCfg;
output.push_back(
FolderPairSyncCfg(syncCfg.directionCfg.var == DirectionConfig::AUTOMATIC,
@@ -286,8 +276,8 @@ std::vector<zen::FolderPairSyncCfg> zen::extractSyncCfg(const MainConfiguration&
}
return output;
}
-//------------------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------------------
//test if user accidentally selected the wrong folders to sync
bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
@@ -301,140 +291,28 @@ bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
return false;
const int nonMatchingRows = folderPairStat.getCreate() +
- //folderPairStat.getUpdate() + -> not relevant when testing for "wrong folder selected"
- folderPairStat.getDelete () +
- folderPairStat.getConflict(); //?
+ folderPairStat.getDelete();
+ //folderPairStat.getUpdate() + -> not relevant when testing for "wrong folder selected"
+ //folderPairStat.getConflict();
return nonMatchingRows >= 10 && nonMatchingRows > 0.5 * folderPairStat.getRowCount();
}
//#################################################################################################################
-/*
-class PhysicalStatistics //counts *physical* operations, actual items processed (NOT disk accesses) and bytes transferred
-{
-public:
- PhysicalStatistics(const FolderComparison& folderCmp) : items(0)
- {
- delType =;
- std::for_each(begin(folderCmp), end(folderCmp), [&](const BaseDirMapping& baseMap) { recurse(baseMap); });
- }
-
- int getItems() const { return items; }
- Int64 getBytes() const { return bytes; }
-
-private:
- enum DeletionType
-{
- DEL_PERMANENTLY,
- DEL_RECYCLE_BIN,
- VERSIONING_SAME_VOL,
- VERSIONING_DIFF_VOL,
-};
-
- void recurse(const HierarchyObject& hierObj)
- {
- std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirObj ) { calcStats(dirObj ); });
- std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileObj) { calcStats(fileObj); });
- std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](const SymLinkMapping& linkObj) { calcStats(linkObj); });
- }
-
- void calcStats(const FileMapping& fileObj)
- {
- switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- items += 2;
- bytes += to<Int64>(fileObj.getFileSize<RIGHT_SIDE>());
- break;
-
- case SO_CREATE_NEW_RIGHT:
- ++items;
- bytes += to<Int64>(fileObj.getFileSize<LEFT_SIDE>());
- break;
-
- case SO_DELETE_LEFT:
- switch (delType)
- {
- case DEL_INSTANTLY:
- ++items;
- break;
- case DEL_COPY_DELETE:
- break;
- }
- break;
-
- case SO_DELETE_RIGHT:
- ++items;
- break;
-
- case SO_MOVE_LEFT_TARGET:
- case SO_MOVE_RIGHT_TARGET:
- ++items;
- break;
-
- case SO_MOVE_LEFT_SOURCE: //ignore; already counted
- case SO_MOVE_RIGHT_SOURCE: //
- break;
-
- case SO_OVERWRITE_LEFT:
- //todo: delete
- items += 2; //read + write
- bytes += to<Int64>(fileObj.getFileSize<RIGHT_SIDE>());
- break;
-
- case SO_OVERWRITE_RIGHT:
- //todo: delete
- items += 2; //read + write
- bytes += to<Int64>(fileObj.getFileSize<LEFT_SIDE>());
- break;
-
- case SO_COPY_METADATA_TO_LEFT:
- case SO_COPY_METADATA_TO_RIGHT:
- ++items;
- break;
-
- case SO_UNRESOLVED_CONFLICT:
- case SO_DO_NOTHING:
- case SO_EQUAL:
- break;
- }
- }
-
- void calcStats(const SymLinkMapping& linkObj)
- {
-
- }
-
- void calcStats(const DirMapping& dirObj)
- {
- //since we model physical stats, we recurse only if deletion variant is "permanently" or "user-defined + different volume",
- //else deletion is done as a single physical operation
- }
-
- int items;
- Int64 bytes;
-
-DeletionType delType;
-};
-*/
-
-//--------------------------------------------------------------------------------------------------------------
-
-class DeletionHandling //e.g. generate name of alternate deletion directory (unique for session AND folder pair)
+class DeletionHandling //abstract deletion variants: permanently, recycle bin, user-defined directory
{
public:
DeletionHandling(DeletionPolicy handleDel, //nothrow!
const Zstring& versioningDir,
VersioningStyle versioningStyle,
const TimeComp& timeStamp,
- size_t folderIndex,
const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback);
~DeletionHandling()
{
- try { tryCleanup(false); } //always (try to) clean up, even if synchronization is aborted!
- catch (...) {}
+ try { tryCleanup(false); }
+ catch (...) {} //always (try to) clean up, even if synchronization is aborted!
/*
do not allow user callback:
- make sure this stays non-blocking!
@@ -445,10 +323,9 @@ public:
//clean-up temporary directory (recycle bin optimization)
void tryCleanup(bool allowUserCallback = true); //throw FileError -> call this in non-exceptional coding, i.e. somewhere after sync!
- void removeFile (const Zstring& relativeName); //throw FileError
- void removeFolder(const Zstring& relativeName) { removeFolderInt(relativeName, nullptr, nullptr); }; //throw FileError
- void removeFolderUpdateStatistics(const Zstring& relativeName, int objectsExpected, Int64 dataExpected) { removeFolderInt(relativeName, &objectsExpected, &dataExpected); }; //throw FileError
- //in contrast to "removeFolder()" this function will update statistics!
+ template <class Function> void removeFileUpdating(const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion); //throw FileError
+ template <class Function> void removeDirUpdating (const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion); //reports ONLY data delta via updateProcessedData()!
+ template <class Function> void removeLinkUpdating(const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion, LinkDescriptor::LinkType lt); //
const std::wstring& getTxtRemovingFile () const { return txtRemovingFile; } //
const std::wstring& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //buffered status texts
@@ -464,7 +341,6 @@ private:
DeletionHandling(const DeletionHandling&);
DeletionHandling& operator=(const DeletionHandling&);
- void removeFolderInt(const Zstring& relativeName, const int* objectsExpected, const Int64* dataExpected); //throw FileError
void setDeletionPolicy(DeletionPolicy newPolicy);
FileVersioner& getOrCreateVersioner() //throw FileError! => dont create in DeletionHandling()!!!
@@ -481,8 +357,9 @@ private:
const TimeComp timeStamp_;
#ifdef FFS_WIN
- Zstring recyclerTmpDirPf; //temporary folder holding files/folders for *deferred* recycling (postfixed with file name separator)
- std::vector<Zstring> toBeRecycled; //full path of files located in temporary folder, waiting to be recycled
+ Zstring getOrCreateRecyclerTempDirPf(); //throw FileError
+ Zstring recyclerTmpDir; //temporary folder holding files/folders for *deferred* recycling
+ std::vector<Zstring> toBeRecycled; //full path of files located in temporary folder, waiting for batch-recycling
bool recFallbackDelPermantently;
#endif
@@ -499,12 +376,28 @@ private:
bool cleanedUp;
};
+namespace
+{
+#ifdef FFS_WIN
+//recycleBinStatus() blocks seriously if recycle bin is really full and drive is slow
+StatusRecycler recycleBinStatusUpdating(const Zstring& dirname, ProcessCallback& procCallback)
+{
+ procCallback.reportStatus(replaceCpy(_("Checking recycle bin availability for folder %x..."), L"%x", fmtFileName(dirname), false));
+
+ auto ft = async([=] { return recycleBinStatus(dirname); });
+
+ while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
+ procCallback.requestUiRefresh(); //may throw!
+ return ft.get();
+}
+#endif
+}
+
DeletionHandling::DeletionHandling(DeletionPolicy handleDel, //nothrow!
const Zstring& versioningDir,
VersioningStyle versioningStyle,
const TimeComp& timeStamp,
- size_t folderIndex,
const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback) :
procCallback_(procCallback),
@@ -520,21 +413,11 @@ DeletionHandling::DeletionHandling(DeletionPolicy handleDel, //nothrow!
{
#ifdef FFS_WIN
if (!baseDirPf.empty())
- if (handleDel == DELETE_TO_RECYCLER && recycleBinStatus(baseDirPf) != STATUS_REC_EXISTS)
+ if (handleDel == DELETE_TO_RECYCLER && recycleBinStatusUpdating(baseDirPf, procCallback_) != STATUS_REC_EXISTS)
{
handleDel = DELETE_PERMANENTLY; //Windows' ::SHFileOperation() will do this anyway, but we have a better and faster deletion routine (e.g. on networks)
recFallbackDelPermantently = true;
}
-
- //assemble temporary recycler bin directory
- if (!baseDirPf_.empty())
- {
- Zstring tempDir = baseDirPf_ + Zstr("FFS ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp);
- if (folderIndex > 0)
- tempDir += Zstr(" [") + numberTo<Zstring>(folderIndex + 1) + Zstr("]"); //e.g. C:\Source\FFS 2012-05-15 131513 [2]
-
- recyclerTmpDirPf = appendSeparator(tempDir);
- }
#endif
setDeletionPolicy(handleDel);
@@ -590,6 +473,51 @@ private:
ProcessCallback& statusHandler_;
const std::wstring txtRecyclingFile;
};
+
+Zstring createUniqueRandomTempDir(const Zstring& baseDirPf) //throw FileError
+{
+ assert(endsWith(baseDirPf, FILE_NAME_SEPARATOR));
+
+ //1. generate random directory name
+ static std::default_random_engine rng(std::time(nullptr)); //a pseudo-random number engine with seconds-precision seed is sufficient!
+ //the alternative std::random_device may not always be available and can even throw an exception!
+
+ const Zstring chars(Zstr("abcdefghijklmnopqrstuvwxyz")
+ Zstr("1234567890"));
+ std::uniform_int_distribution<size_t> distrib(0, chars.size() - 1); //takes closed range
+
+ auto generatePath = [&]() -> Zstring //e.g. C:\Source\3vkf74fq.ffs_tmp
+ {
+ Zstring path = baseDirPf;
+ for (int i = 0; i < 8; ++i)
+ path += chars[distrib(rng)];
+ return path + TEMP_FILE_ENDING;
+ };
+
+ //2. ensure uniqueness (at least for this base directory)
+ for (;;)
+ try
+ {
+ Zstring dirname = generatePath();
+ makeNewDirectory(dirname, Zstring(), false); //FileError, ErrorTargetExisting
+ return dirname;
+ }
+ catch (const ErrorTargetExisting&) {}
+}
+}
+
+//create + returns temporary directory postfixed with file name separator
+//to support later cleanup if automatic deletion fails for whatever reason
+Zstring DeletionHandling::getOrCreateRecyclerTempDirPf() //throw FileError
+{
+ assert(!baseDirPf_.empty());
+ if (baseDirPf_.empty())
+ return Zstring();
+
+ if (recyclerTmpDir.empty())
+ recyclerTmpDir = createUniqueRandomTempDir(baseDirPf_); //throw FileError
+ //assemble temporary recycle bin directory with random name and .ffs_tmp ending
+ return appendSeparator(recyclerTmpDir);
}
#endif
@@ -604,14 +532,14 @@ void DeletionHandling::tryCleanup(bool allowUserCallback) //throw FileError
case DELETE_TO_RECYCLER:
#ifdef FFS_WIN
- if (!recyclerTmpDirPf.empty())
+ if (!recyclerTmpDir.empty())
{
//move content of temporary directory to recycle bin in a single call
CallbackMassRecycling cbmr(procCallback_);
recycleOrDelete(toBeRecycled, allowUserCallback ? &cbmr : nullptr); //throw FileError
//clean up temp directory itself (should contain remnant empty directories only)
- removeDirectory(beforeLast(recyclerTmpDirPf, FILE_NAME_SEPARATOR)); //throw FileError
+ removeDirectory(recyclerTmpDir); //throw FileError
}
#endif
break;
@@ -634,169 +562,178 @@ void DeletionHandling::tryCleanup(bool allowUserCallback) //throw FileError
}
}
-
namespace
{
-class CallbackMoveFileImpl : public CallbackMoveFile
+template <class Function>
+struct CallbackRemoveDirImpl : public CallbackRemoveDir
{
-public:
- CallbackMoveFileImpl(ProcessCallback& statusHandler,
- int* objectsReported) :
- statusHandler_ (statusHandler),
- objectsReported_(objectsReported),
- txtMovingFile (_("Moving file %x to %y")),
- txtMovingFolder (_("Moving folder %x to %y")) {}
+ CallbackRemoveDirImpl(ProcessCallback& statusHandler,
+ const DeletionHandling& delHandling,
+ Function notifyItemDeletion) :
+ statusHandler_(statusHandler),
+ notifyItemDeletion_(notifyItemDeletion),
+ txtDeletingFile (delHandling.getTxtRemovingFile()),
+ txtDeletingFolder(delHandling.getTxtRemovingDir ()) {}
private:
- 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_)
- {
- statusHandler_.updateProcessedData(1, 0);
- ++*objectsReported_;
- }
- }
+ virtual void onBeforeFileDeletion(const Zstring& filename) { notifyDeletion(txtDeletingFile, filename); }
+ virtual void onBeforeDirDeletion (const Zstring& dirname ) { notifyDeletion(txtDeletingFolder, dirname ); }
- virtual void updateStatus(Int64 bytesDelta)
+ void notifyDeletion(const std::wstring& statusText, const Zstring& objName)
{
- //statusHandler_.updateProcessedData(0, bytesDelta);
- //bytesReported_ += bytesDelta; -> statistics model *logical* operations! as such a file delete is only (1 obj/0 bytes)! Doesn't matter if it's actually copy + delete
-
- statusHandler_.requestUiRefresh();
+ notifyItemDeletion_(); //it would be more correct to report *after* work was done!
+ statusHandler_.reportStatus(replaceCpy(statusText, L"%x", fmtFileName(objName)));
}
- void reportStatus(const std::wstring& statusText, const Zstring& fileFrom, const Zstring& fileTo) const
- {
- statusHandler_.reportStatus(replaceCpy(replaceCpy(statusText, L"%x", fmtFileName(fileFrom)), L"%y", fmtFileName(fileTo)));
- };
-
ProcessCallback& statusHandler_;
- int* objectsReported_; //optional
-
- const std::wstring txtMovingFile;
- const std::wstring txtMovingFolder;
+ Function notifyItemDeletion_;
+ const std::wstring txtDeletingFile;
+ const std::wstring txtDeletingFolder;
};
-struct CallbackRemoveDirImpl : public CallbackRemoveDir
+template <class Function>
+class CallbackMoveDirImpl : public CallbackMoveDir
{
- CallbackRemoveDirImpl(ProcessCallback& statusHandler,
- const DeletionHandling& delHandling,
- int* objectsReported) :
- statusHandler_(statusHandler),
- delHandling_(delHandling),
- objectsReported_(objectsReported) {}
+public:
+ CallbackMoveDirImpl(ProcessCallback& callback,
+ Int64& bytesReported,
+ Function notifyItemDeletion) :
+ callback_ (callback),
+ bytesReported_(bytesReported),
+ notifyItemDeletion_(notifyItemDeletion),
+ txtMovingFile (_("Moving file %x to %y")),
+ txtMovingFolder (_("Moving folder %x to %y")) {}
private:
- virtual void notifyFileDeletion(const Zstring& filename) { processSingleObject(delHandling_.getTxtRemovingFile(), filename); }
- virtual void notifyDirDeletion (const Zstring& dirname ) { processSingleObject(delHandling_.getTxtRemovingDir (), dirname ); }
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) { notifyMove(txtMovingFile, fileFrom, fileTo); }
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) { notifyMove(txtMovingFolder, dirFrom, dirTo); }
- void processSingleObject(const std::wstring& statusText, const Zstring& objName)
+ void notifyMove(const std::wstring& statusText, const Zstring& fileFrom, const Zstring& fileTo) const
{
- statusHandler_.reportStatus(replaceCpy(statusText, L"%x", fmtFileName(objName)));
+ notifyItemDeletion_(); //it would be more correct to report *after* work was done!
+ callback_.reportStatus(replaceCpy(replaceCpy(statusText, L"%x", fmtFileName(fileFrom)), L"%y", fmtFileName(fileTo)));
+ };
- if (objectsReported_)
- {
- statusHandler_.updateProcessedData(1, 0);
- ++*objectsReported_;
- }
+ virtual void updateStatus(Int64 bytesDelta)
+ {
+ callback_.updateProcessedData(0, bytesDelta); //throw()! -> ensure client and service provider are in sync!
+ bytesReported_ += bytesDelta; //
+
+ callback_.requestUiRefresh(); //may throw
}
- ProcessCallback& statusHandler_;
- const DeletionHandling& delHandling_;
- int* objectsReported_; //optional
+ ProcessCallback& callback_;
+ Int64& bytesReported_;
+ Function notifyItemDeletion_;
+ const std::wstring txtMovingFile;
+ const std::wstring txtMovingFolder;
};
}
-void DeletionHandling::removeFile(const Zstring& relativeName)
+template <class Function>
+void DeletionHandling::removeDirUpdating(const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion) //throw FileError
{
+ assert(!baseDirPf_.empty());
const Zstring fullName = baseDirPf_ + relativeName;
+ Int64 bytesReported;
+ ScopeGuard guardStatistics = makeGuard([&] { procCallback_.updateTotalData(0, bytesReported); }); //error = unexpected increase of total workload
+
switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
- zen::removeFile(fullName);
- //[!] scope specifier resolves nameclash!
- break;
+ {
+ CallbackRemoveDirImpl<Function> remDirCallback(procCallback_, *this, notifyItemDeletion);
+ removeDirectory(fullName, &remDirCallback);
+ }
+ break;
case DELETE_TO_RECYCLER:
+ {
#ifdef FFS_WIN
- {
- const Zstring targetFile = recyclerTmpDirPf + relativeName; //ends with path separator
+ const Zstring targetDir = getOrCreateRecyclerTempDirPf() + relativeName; //throw FileError
+ bool deleted = false;
- auto moveToTempDir = [&]
- {
- //performance optimization: Instead of moving each object into recycle bin separately,
- //we rename them one by one into a temporary directory and batch-recycle this directory after sync
- renameFile(fullName, targetFile); //throw FileError
- toBeRecycled.push_back(targetFile);
- };
+ auto moveToTempDir = [&]
+ {
+ //performance optimization: Instead of moving each object into recycle bin separately,
+ //we rename them one by one into a temporary directory and batch-recycle this directory after sync
+ renameFile(fullName, targetDir); //throw FileError
+ this->toBeRecycled.push_back(targetDir);
+ deleted = true;
+ };
- try
- {
- moveToTempDir(); //throw FileError
- }
- catch (FileError&)
+ try
+ {
+ moveToTempDir(); //throw FileError
+ }
+ catch (FileError&)
+ {
+ if (somethingExists(fullName))
{
- if (somethingExists(fullName))
+ const Zstring targetSuperDir = beforeLast(targetDir, FILE_NAME_SEPARATOR);
+ if (!dirExists(targetSuperDir))
{
- const Zstring targetDir = beforeLast(targetFile, FILE_NAME_SEPARATOR);
- if (!dirExists(targetDir))
- {
- makeDirectory(targetDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
- moveToTempDir(); //throw FileError -> this should work now!
- }
- else
- throw;
+ makeDirectory(targetSuperDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ moveToTempDir(); //throw FileError -> this should work now!
}
+ else
+ throw;
}
}
#elif defined FFS_LINUX
- recycleOrDelete(fullName); //throw FileError
+ const bool deleted = recycleOrDelete(fullName); //throw FileError
#endif
- break;
+ if (deleted)
+ notifyItemDeletion(); //moving to recycler is ONE logical operation, irrespective of the number of child elements!
+ }
+ break;
case DELETE_TO_VERSIONING:
{
- CallbackMoveFileImpl callback(procCallback_, nullptr); //we do *not* report statistics in this method
- getOrCreateVersioner().revisionFile(fullName, relativeName, callback); //throw FileError
+ CallbackMoveDirImpl<Function> callback(procCallback_, bytesReported, notifyItemDeletion);
+ getOrCreateVersioner().revisionDir(fullName, relativeName, callback); //throw FileError
}
break;
}
+
+ //update statistics to consider the real amount of data
+ guardStatistics.dismiss();
+ if (bytesReported != bytesExpected)
+ procCallback_.updateTotalData(0, bytesReported - bytesExpected); //noexcept!
}
-void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* objectsExpected, const Int64* dataExpected) //throw FileError
+template <class Function>
+void DeletionHandling::removeFileUpdating(const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion) //throw FileError
{
+ assert(!baseDirPf_.empty());
const Zstring fullName = baseDirPf_ + relativeName;
- int objectsReported = 0; //use *only* if "objectsExpected" is bound!
- //in error situation: undo communication of processed amount of data
- ScopeGuard guardStatistics = makeGuard([&] { procCallback_.updateProcessedData(-objectsReported, 0); });
+ Int64 bytesReported;
+ auto guardStatistics = makeGuard([&] { procCallback_.updateTotalData(0, bytesReported); }); //error = unexpected increase of total workload
+ bool deleted = false;
switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
- {
- CallbackRemoveDirImpl remDirCallback(procCallback_, *this, objectsExpected ? &objectsReported : nullptr);
- removeDirectory(fullName, &remDirCallback);
- }
- break;
+ deleted = zen::removeFile(fullName); //[!] scope specifier resolves nameclash!
+ break;
case DELETE_TO_RECYCLER:
#ifdef FFS_WIN
{
- const Zstring targetDir = recyclerTmpDirPf + relativeName;
+ const Zstring targetFile = getOrCreateRecyclerTempDirPf() + relativeName; //throw FileError
auto moveToTempDir = [&]
{
//performance optimization: Instead of moving each object into recycle bin separately,
//we rename them one by one into a temporary directory and batch-recycle this directory after sync
- renameFile(fullName, targetDir); //throw FileError
- toBeRecycled.push_back(targetDir);
+ renameFile(fullName, targetFile); //throw FileError
+ this->toBeRecycled.push_back(targetFile);
+ deleted = true;
};
try
@@ -807,10 +744,10 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
{
if (somethingExists(fullName))
{
- const Zstring targetSuperDir = beforeLast(targetDir, FILE_NAME_SEPARATOR);
- if (!dirExists(targetSuperDir))
+ const Zstring targetDir = beforeLast(targetFile, FILE_NAME_SEPARATOR);
+ if (!dirExists(targetDir))
{
- makeDirectory(targetSuperDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ makeDirectory(targetDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
moveToTempDir(); //throw FileError -> this should work now!
}
else
@@ -819,31 +756,51 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
}
}
#elif defined FFS_LINUX
- recycleOrDelete(fullName); //throw FileError
+ deleted = recycleOrDelete(fullName); //throw FileError
#endif
-
- if (objectsExpected) //even though we have only one disk access, we completed "objectsExpected" logical operations!
- {
- procCallback_.updateProcessedData(*objectsExpected, 0);
- objectsReported += *objectsExpected;
- }
break;
case DELETE_TO_VERSIONING:
{
- CallbackMoveFileImpl callback(procCallback_, objectsExpected ? &objectsReported : nullptr);
- getOrCreateVersioner().revisionDir(fullName, relativeName, callback); //throw FileError
+ struct CallbackMoveFileImpl : public CallbackMoveFile
+ {
+ CallbackMoveFileImpl(ProcessCallback& callback, Int64& bytes) : callback_(callback), bytesReported_(bytes) {}
+
+ private:
+ virtual void updateStatus(Int64 bytesDelta)
+ {
+ callback_.updateProcessedData(0, bytesDelta); //throw()! -> ensure client and service provider are in sync!
+ bytesReported_ += bytesDelta; //
+
+ callback_.requestUiRefresh(); //may throw
+ }
+ ProcessCallback& callback_;
+ Int64& bytesReported_;
+ } cb(procCallback_, bytesReported);
+
+ deleted = getOrCreateVersioner().revisionFile(fullName, relativeName, cb); //throw FileError
}
break;
}
+ if (deleted)
+ notifyItemDeletion();
+
+ //update statistics to consider the real amount of data
+ guardStatistics.dismiss();
+ if (bytesReported != bytesExpected)
+ procCallback_.updateTotalData(0, bytesReported - bytesExpected); //noexcept!
+}
- //inform about the (remaining) processed amount of data
- if (objectsExpected && dataExpected)
+template <class Function> inline
+void DeletionHandling::removeLinkUpdating(const Zstring& relativeName, Int64 bytesExpected, Function notifyItemDeletion, LinkDescriptor::LinkType lt) //throw FileError
+{
+ switch (lt)
{
- guardStatistics.dismiss();
+ case LinkDescriptor::TYPE_DIR:
+ return removeDirUpdating(relativeName, bytesExpected, notifyItemDeletion); //throw FileError
- if (*objectsExpected != objectsReported || *dataExpected != 0) //adjust total: may have changed after comparison!
- procCallback_.updateTotalData(objectsReported - *objectsExpected, -*dataExpected);
+ case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
+ return removeFileUpdating(relativeName, bytesExpected, notifyItemDeletion); //throw FileError
}
}
@@ -1033,9 +990,8 @@ private:
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>
- void copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const;
+ template <SelectedSide sideTrg, class Function>
+ FileAttrib copyFileUpdatingTo(const FileMapping& fileObj, Function delTargetCommand) const; //throw FileError; reports data delta via updateProcessedData()
void verifyFileCopy(const Zstring& source, const Zstring& target) const;
template <SelectedSide side>
@@ -1115,7 +1071,7 @@ Zstring findUnusedTempName(const Zstring& filename)
{
Zstring output = filename + zen::TEMP_FILE_ENDING;
- //ensure uniqueness
+ //ensure uniqueness (+ minor file system race condition!)
for (int i = 1; somethingExists(output); ++i)
output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
@@ -1437,8 +1393,8 @@ void SynchronizeFolderPair::runPass(HierarchyObject& hierObj)
this->runPass<pass>(dirObj); //recurse
});
}
-//---------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------
namespace
{
@@ -1503,26 +1459,25 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
case SO_CREATE_NEW_RIGHT:
{
const Zstring& target = fileObj.getBaseDirPf<sideTrg>() + fileObj.getRelativeName<sideSrc>(); //can't use "getFullName" as target is not yet existing
-
reportInfo(txtCreatingFile, target);
try
{
- FileAttrib newAttr;
- copyFileUpdatingTo<sideTrg>(fileObj, [] {}, /*no target to delete*/ newAttr); //throw FileError
- procCallback_.updateProcessedData(1, 0); //processed data is communicated in copyFileUpdatingTo()!
+ const FileAttrib newAttr = copyFileUpdatingTo<sideTrg>(fileObj, [] {} /*no target to delete*/); //throw FileError
const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId);
const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId);
fileObj.syncTo<sideTrg>(descrTarget, &descrSource); //update FileMapping
+
+ procCallback_.updateProcessedData(1, 0); //processed bytes are reported in copyFileUpdatingTo()!
}
catch (FileError&)
{
- if (somethingExists(fileObj.getFullName<sideSrc>())) //do not check on type (symlink, file, folder) -> if there is a type change, FFS should not be quiet about it!
+ if (somethingExists(fileObj.getFullName<sideSrc>())) //do not check on type (symlink, file, folder) -> if there is a type change, FFS should error out!
throw;
//source deleted meanwhile...nothing was done (logical point of view!)
- procCallback_.updateTotalData(-1, -to<zen::Int64>(fileObj.getFileSize<sideSrc>()));
fileObj.removeObject<sideSrc>();
+ procCallback_.updateTotalData(-1, -to<zen::Int64>(fileObj.getFileSize<sideSrc>()));
}
}
break;
@@ -1530,11 +1485,23 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
case SO_DELETE_LEFT:
case SO_DELETE_RIGHT:
reportInfo(getDelHandling<sideTrg>().getTxtRemovingFile(), fileObj.getFullName<sideTrg>());
+ {
+ int objectsReported = 0;
+ auto guardStatistics = makeGuard([&] { procCallback_.updateTotalData(objectsReported, 0); }); //error = unexpected increase of total workload
+ const int objectsExpected = 1;
+ const Int64 bytesExpected = 0;
- getDelHandling<sideTrg>().removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<sideTrg>(); //update FileMapping
+ getDelHandling<sideTrg>().removeFileUpdating(fileObj.getObjRelativeName(), bytesExpected, [&] //throw FileError
+ {
+ procCallback_.updateProcessedData(1, 0); //noexcept
+ ++objectsReported;
+ });
- procCallback_.updateProcessedData(1, 0);
+ guardStatistics.dismiss(); //update statistics to consider the real amount of data
+ if (objectsReported != objectsExpected)
+ procCallback_.updateTotalData(objectsReported - objectsExpected, 0); //noexcept!
+ }
+ fileObj.removeObject<sideTrg>(); //update FileMapping
break;
case SO_MOVE_LEFT_SOURCE:
@@ -1562,8 +1529,8 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
sourceObj->getFileSize <sideTrg>(),
sourceObj->getFileId <sideTrg>());
- sourceObj->removeObject<sideTrg>(); //
- targetObj->syncTo<sideTrg>(descrTarget); //update FileMapping
+ sourceObj->removeObject<sideTrg>(); //update FileMapping
+ targetObj->syncTo<sideTrg>(descrTarget); //
procCallback_.updateProcessedData(1, 0);
}
@@ -1573,25 +1540,24 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
case SO_OVERWRITE_RIGHT:
{
const Zstring& target = fileObj.getBaseDirPf<sideTrg>() + fileObj.getRelativeName<sideSrc>(); //respect differences in case of source object
-
reportInfo(txtOverwritingFile, target);
- FileAttrib newAttr;
- copyFileUpdatingTo<sideTrg>(fileObj, [&] //delete target at appropriate time
+ const FileAttrib newAttr = copyFileUpdatingTo<sideTrg>(fileObj, [&] //delete target at appropriate time
{
reportStatus(this->getDelHandling<sideTrg>().getTxtRemovingFile(), fileObj.getFullName<sideTrg>());
- this->getDelHandling<sideTrg>().removeFile(fileObj.getObjRelativeName()); //throw FileError
- fileObj.removeObject<sideTrg>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
+ this->getDelHandling<sideTrg>().removeFileUpdating(fileObj.getObjRelativeName(), 0, []{}); //throw FileError;
+ //no (logical) item count update desired - but total byte count may change, e.g. move(copy) deleted file to versioning dir
+ fileObj.removeObject<sideTrg>(); //update FileMapping
reportStatus(txtOverwritingFile, target); //restore status text copy file
- }, newAttr);
+ });
const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId);
const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId);
fileObj.syncTo<sideTrg>(descrTarget, &descrSource); //update FileMapping
- procCallback_.updateProcessedData(1, 0);
+ procCallback_.updateProcessedData(1, 0); //we model "delete + copy" as ONE logical operation
}
break;
@@ -1649,20 +1615,6 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
{
static const SelectedSide sideSrc = OtherSide<sideTrg>::result;
- auto deleteSymlink = [&]
- {
- switch (linkObj.getLinkType<sideTrg>())
- {
- case LinkDescriptor::TYPE_DIR:
- this->getDelHandling<sideTrg>().removeFolder(linkObj.getObjRelativeName()); //throw FileError
- break;
-
- case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link
- this->getDelHandling<sideTrg>().removeFile(linkObj.getObjRelativeName()); //throw FileError
- break;
- }
- };
-
switch (syncOp)
{
case SO_CREATE_NEW_LEFT:
@@ -1675,17 +1627,17 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
try
{
zen::copySymlink(linkObj.getFullName<sideSrc>(), target, copyFilePermissions_); //throw FileError
- procCallback_.updateProcessedData(1, 0);
-
linkObj.copyTo<sideTrg>(); //update SymLinkMapping
+
+ procCallback_.updateProcessedData(1, 0);
}
catch (FileError&)
{
if (somethingExists(linkObj.getFullName<sideSrc>())) //do not check on type (symlink, file, folder) -> if there is a type change, FFS should not be quiet about it!
throw;
//source deleted meanwhile...nothing was done (logical point of view!)
- procCallback_.updateTotalData(-1, 0);
linkObj.removeObject<sideSrc>();
+ procCallback_.updateTotalData(-1, 0);
}
}
break;
@@ -1693,12 +1645,23 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
case SO_DELETE_LEFT:
case SO_DELETE_RIGHT:
reportInfo(getDelHandling<sideTrg>().getTxtRemovingSymLink(), linkObj.getFullName<sideTrg>());
+ {
+ int objectsReported = 0;
+ auto guardStatistics = makeGuard([&] { procCallback_.updateTotalData(objectsReported, 0); }); //error = unexpected increase of total workload
+ const int objectsExpected = 1;
+ const Int64 bytesExpected = 0;
- deleteSymlink(); //throw FileError
+ getDelHandling<sideTrg>().removeLinkUpdating(linkObj.getObjRelativeName(), bytesExpected, [&] //throw FileError
+ {
+ procCallback_.updateProcessedData(1, 0); //noexcept
+ ++objectsReported;
+ }, linkObj.getLinkType<sideTrg>());
+ guardStatistics.dismiss(); //update statistics to consider the real amount of data
+ if (objectsReported != objectsExpected)
+ procCallback_.updateTotalData(objectsReported - objectsExpected, 0); //noexcept!
+ }
linkObj.removeObject<sideTrg>(); //update SymLinkMapping
-
- procCallback_.updateProcessedData(1, 0);
break;
case SO_OVERWRITE_LEFT:
@@ -1709,14 +1672,14 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
reportInfo(txtOverwritingLink, target);
reportStatus(getDelHandling<sideTrg>().getTxtRemovingSymLink(), linkObj.getFullName<sideTrg>());
- deleteSymlink(); //throw FileError
+ getDelHandling<sideTrg>().removeLinkUpdating(linkObj.getObjRelativeName(), 0, []{}, linkObj.getLinkType<sideTrg>()); //throw FileError
linkObj.removeObject<sideTrg>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!)
reportStatus(txtOverwritingLink, target); //restore status text
zen::copySymlink(linkObj.getFullName<sideSrc>(), target, copyFilePermissions_); //throw FileError
linkObj.copyTo<sideTrg>(); //update SymLinkMapping
- procCallback_.updateProcessedData(1, 0);
+ procCallback_.updateProcessedData(1, 0); //we model "delete + copy" as ONE logical operation
}
break;
@@ -1730,7 +1693,6 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
if (!sameFileTime(linkObj.getLastWriteTime<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), 2)) //respect 2 second FAT/FAT32 precision
setFileTime(linkObj.getFullName<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), SYMLINK_DIRECT); //throw FileError
-
linkObj.copyTo<sideTrg>(); //-> both sides *should* be completely equal now...
procCallback_.updateProcessedData(1, 0);
@@ -1777,32 +1739,57 @@ void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperati
{
case SO_CREATE_NEW_LEFT:
case SO_CREATE_NEW_RIGHT:
- if (somethingExists(dirObj.getFullName<sideSrc>())) //do not check on type (symlink, file, folder) -> if there is a type change, FFS should not be quiet about it!
+ if (somethingExists(dirObj.getFullName<sideSrc>())) //do not check on type (symlink, file, folder) -> if there is a type change, FFS should error out!
{
const Zstring& target = dirObj.getBaseDirPf<sideTrg>() + dirObj.getRelativeName<sideSrc>();
reportInfo(txtCreatingFolder, target);
try
{
- makeNewDirectory(target, dirObj.getFullName<sideSrc>(), copyFilePermissions_); //no symlink copying!
+ makeNewDirectory(target, dirObj.getFullName<sideSrc>(), copyFilePermissions_); //throw FileError, ErrorTargetExisting
}
- catch (const ErrorTargetExisting&) { if (!dirExists(target)) throw; } //clash with file (dir-symlink is okay)
-
+ catch (const ErrorTargetExisting&) { if (!dirExists(target)) throw; } //detect clash with file (dir-symlink OTOH is okay)
dirObj.copyTo<sideTrg>(); //update DirMapping
procCallback_.updateProcessedData(1, 0);
}
else //source deleted meanwhile...nothing was done (logical point of view!) -> uh....what about a temporary network drop???
{
- // throw FileError
+ dirObj.refSubFiles().clear(); //
+ dirObj.refSubLinks().clear(); //update DirMapping
+ dirObj.refSubDirs ().clear(); //
+ dirObj.removeObject<sideSrc>(); //
+
const SyncStatistics subStats(dirObj);
procCallback_.updateTotalData(-getCUD(subStats) - 1, -subStats.getDataToProcess());
+ }
+ break;
- dirObj.refSubFiles().clear(); //...then remove sub-objects
- dirObj.refSubLinks().clear(); //
- dirObj.refSubDirs ().clear(); //
- dirObj.removeObject<sideSrc>();
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ reportInfo(getDelHandling<sideTrg>().getTxtRemovingDir(), dirObj.getFullName<sideTrg>());
+ {
+ int objectsReported = 0;
+ auto guardStatistics = makeGuard([&] { procCallback_.updateTotalData(objectsReported, 0); }); //error = unexpected increase of total workload
+ const SyncStatistics subStats(dirObj); //counts sub-objects only!
+ const int objectsExpected = 1 + getCUD(subStats);
+ const Int64 bytesExpected = subStats.getDataToProcess();
+ assert(bytesExpected == 0);
+
+ getDelHandling<sideTrg>().removeDirUpdating(dirObj.getObjRelativeName(), bytesExpected, [&] //throw FileError
+ {
+ procCallback_.updateProcessedData(1, 0); //noexcept
+ ++objectsReported;
+ });
+
+ guardStatistics.dismiss(); //update statistics to consider the real amount of data
+ if (objectsReported != objectsExpected)
+ procCallback_.updateTotalData(objectsReported - objectsExpected, 0); //noexcept!
}
+ dirObj.refSubFiles().clear(); //
+ dirObj.refSubLinks().clear(); //update DirMapping
+ dirObj.refSubDirs ().clear(); //
+ dirObj.removeObject<sideTrg>(); //
break;
case SO_COPY_METADATA_TO_LEFT:
@@ -1812,29 +1799,12 @@ void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperati
if (dirObj.getShortName<sideTrg>() != dirObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
renameFile(dirObj.getFullName<sideTrg>(),
beforeLast(dirObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<sideSrc>()); //throw FileError
- //copyFileTimes -> useless at this time: modification time changes with each child-object creation/deletion
-
+ //copyFileTimes -> useless: modification time changes with each child-object creation/deletion
dirObj.copyTo<sideTrg>(); //-> both sides *should* be completely equal now...
procCallback_.updateProcessedData(1, 0);
break;
- case SO_DELETE_LEFT:
- case SO_DELETE_RIGHT:
- {
- reportInfo(getDelHandling<sideTrg>().getTxtRemovingDir(), dirObj.getFullName<sideTrg>());
-
- const SyncStatistics subStats(dirObj); //counts sub-objects only!
- getDelHandling<sideTrg>().removeFolderUpdateStatistics(dirObj.getObjRelativeName(), 1 + getCUD(subStats), subStats.getDataToProcess()); //throw FileError
- //this call covers progress indicator updates for dir + sub-objects!
-
- dirObj.refSubFiles().clear(); //...then remove everything
- dirObj.refSubLinks().clear(); //
- dirObj.refSubDirs ().clear(); //
- dirObj.removeObject<sideTrg>(); //
- }
- break;
-
case SO_OVERWRITE_RIGHT:
case SO_OVERWRITE_LEFT:
case SO_MOVE_LEFT_SOURCE:
@@ -1936,7 +1906,7 @@ void zen::synchronize(const TimeComp& timeStamp,
//specify process and resource handling priorities
std::unique_ptr<ScheduleForBackgroundProcessing> backgroundPrio;
if (runWithBackgroundPriority)
- backgroundPrio.reset(new ScheduleForBackgroundProcessing);
+ backgroundPrio = make_unique<ScheduleForBackgroundProcessing>();
//prevent operating system going into sleep state
PreventStandby dummy;
@@ -1971,7 +1941,6 @@ void zen::synchronize(const TimeComp& timeStamp,
folderPairCfg.versioningFolder,
folderPairCfg.versioningStyle_,
timeStamp,
- folderIndex,
j->getBaseDirPf<LEFT_SIDE>(),
callback);
@@ -1979,7 +1948,6 @@ void zen::synchronize(const TimeComp& timeStamp,
folderPairCfg.versioningFolder,
folderPairCfg.versioningStyle_,
timeStamp,
- folderIndex,
j->getBaseDirPf<RIGHT_SIDE>(),
callback);
}
@@ -2209,11 +2177,11 @@ void zen::synchronize(const TimeComp& timeStamp,
{
std::wstring warningMessage = _("Not enough free disk space available in:");
- for (auto i = diskSpaceMissing.begin(); i != diskSpaceMissing.end(); ++i)
+ for (auto it = diskSpaceMissing.begin(); it != diskSpaceMissing.end(); ++it)
warningMessage += std::wstring(L"\n\n") +
- fmtFileName(i->first) + L"\n" +
- _("Required:") + L" " + filesizeToShortString(i->second.first) + L"\n" +
- _("Available:") + L" " + filesizeToShortString(i->second.second);
+ fmtFileName(it->first) + L"\n" +
+ _("Required:") + L" " + filesizeToShortString(it->second.first) + L"\n" +
+ _("Available:") + L" " + filesizeToShortString(it->second.second);
callback.reportWarning(warningMessage, warnings.warningNotEnoughDiskSpace);
}
@@ -2246,8 +2214,8 @@ void zen::synchronize(const TimeComp& timeStamp,
if (!conflictDirs.empty())
{
std::wstring warningMessage = _("A folder 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 += L"\n" + fmtFileName(*i);
+ for (auto it = conflictDirs.begin(); it != conflictDirs.end(); ++it)
+ warningMessage += L"\n" + fmtFileName(*it);
callback.reportWarning(warningMessage, warnings.warningFolderPairRaceCondition);
}
@@ -2343,61 +2311,58 @@ void zen::synchronize(const TimeComp& timeStamp,
}
}
-
//###########################################################################################
-//callback functionality for smooth progress indicators
-template <class DelTargetCommand>
+template <class Function>
class WhileCopying : public zen::CallbackCopyFile
{
public:
WhileCopying(Int64& bytesReported,
ProcessCallback& statusHandler,
- const DelTargetCommand& cmd) :
+ Function delTargetCmd) :
bytesReported_(bytesReported),
statusHandler_(statusHandler),
- cmd_(cmd) {}
+ delTargetCmd_(std::move(delTargetCmd)) {}
- virtual void deleteTargetFile(const Zstring& targetFile) { cmd_(); }
+ virtual void deleteTargetFile(const Zstring& targetFile) { delTargetCmd_(); }
virtual void updateCopyStatus(Int64 bytesDelta)
{
- //inform about the (differential) processed amount of data
- statusHandler_.updateProcessedData(0, bytesDelta); //throw()! -> this ensures client and service provider are in sync!
+ statusHandler_.updateProcessedData(0, bytesDelta); //throw()! -> ensure client and service provider are in sync!
bytesReported_ += bytesDelta; //
statusHandler_.requestUiRefresh(); //may throw
}
private:
- Int64& bytesReported_;
+ Int64& bytesReported_;
ProcessCallback& statusHandler_;
- DelTargetCommand cmd_;
+ Function delTargetCmd_;
};
-//copy file while refreshing UI
-template <SelectedSide side, class DelTargetCommand>
-void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const
+//throw FileError; reports data delta via updateProcessedData()
+template <SelectedSide sideTrg, class Function>
+FileAttrib SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, Function delTargetCommand) const //returns current attributes of source file
{
- const Int64 expectedBytesToCpy = to<Int64>(fileObj.getFileSize<OtherSide<side>::result>());
- Zstring source = fileObj.getFullName<OtherSide<side>::result>();
- const Zstring& target = fileObj.getBaseDirPf<side>() + fileObj.getRelativeName<OtherSide<side>::result>();
+ static const SelectedSide sideSrc = OtherSide<sideTrg>::result;
+
+ FileAttrib newAttr;
+ const Int64 bytesExpected = to<Int64>(fileObj.getFileSize<sideSrc>());
+ Zstring source = fileObj.getFullName<sideSrc>();
+ const Zstring& target = fileObj.getBaseDirPf<sideTrg>() + fileObj.getRelativeName<sideSrc>();
Int64 bytesReported;
auto copyOperation = [&]
{
- //start of (possibly) long-running copy process: ensure status updates are performed regularly
-
- //in error situation: undo communication of processed amount of data
auto guardStatistics = makeGuard([&]
{
- procCallback_.updateProcessedData(0, -bytesReported);
+ procCallback_.updateTotalData(0, bytesReported); //error = unexpected increase of total workload
bytesReported = 0;
});
- WhileCopying<DelTargetCommand> callback(bytesReported, procCallback_, cmd);
+ WhileCopying<Function> callback(bytesReported, procCallback_, delTargetCommand);
copyFile(source, //type File implicitly means symlinks need to be dereferenced!
target,
@@ -2415,11 +2380,10 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
}
//#################### /Verification #############################
- //update statistics to consider the real amount of data, e.g. more than the "file size" for ADS streams or file changed in the meantime!
- if (bytesReported != expectedBytesToCpy)
- procCallback_.updateTotalData(0, bytesReported - expectedBytesToCpy);
-
- //we model physical statistic numbers => adjust total: consider ADS, sparse, compressed files -> transferred bytes may differ from file size (which is just a rough guess)!
+ //update statistics to consider the real amount of data, e.g. more than the "file size" for ADS streams,
+ //less for sparse and compressed files, or file changed in the meantime!
+ if (bytesReported != bytesExpected)
+ procCallback_.updateTotalData(0, bytesReported - bytesExpected); //noexcept!
guardStatistics.dismiss();
};
@@ -2450,6 +2414,8 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
#else
copyOperation();
#endif
+
+ return newAttr;
}
diff --git a/synchronization.h b/synchronization.h
index 3a3dcec1..e9d15e29 100644
--- a/synchronization.h
+++ b/synchronization.h
@@ -41,7 +41,6 @@ public:
size_t getRowCount() const { return rowsTotal; }
private:
- //static const size_t MAX_CONFLICTS = 3;
void init();
void recurse(const HierarchyObject& hierObj);
@@ -53,7 +52,6 @@ private:
int createLeft, createRight;
int updateLeft, updateRight;
int deleteLeft, deleteRight;
- // int conflict;
ConflictTexts conflictMsgs; //conflict texts to display as a warning message
Int64 dataToProcess;
size_t rowsTotal;
diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp
index ebfa84a0..9e8b1489 100644
--- a/ui/batch_status_handler.cpp
+++ b/ui/batch_status_handler.cpp
@@ -225,7 +225,7 @@ BatchStatusHandler::~BatchStatusHandler()
showFinalResults = false; //take precedence over current visibility status
else if (!finalCommand.empty())
{
- auto cmdexp = utfCvrtTo<wxString>(expandMacros(utfCvrtTo<Zstring>(finalCommand)));
+ auto cmdexp = expandMacros(utfCvrtTo<Zstring>(finalCommand));
shellExecute(cmdexp);
}
}
@@ -262,17 +262,7 @@ void BatchStatusHandler::updateProcessedData(int objectsDelta, Int64 dataDelta)
{
StatusHandler::updateProcessedData(objectsDelta, dataDelta);
- switch (currentPhase())
- {
- 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;
- }
+ syncStatusFrame.notifyProgressChange(); //noexcept
//note: this method should NOT throw in order to properly allow undoing setting of statistics!
}
@@ -415,7 +405,7 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
void BatchStatusHandler::forceUiRefresh()
{
- syncStatusFrame.updateProgress();
+ syncStatusFrame.updateGui();
}
diff --git a/ui/check_version.cpp b/ui/check_version.cpp
index c9d2049d..922708c7 100644
--- a/ui/check_version.cpp
+++ b/ui/check_version.cpp
@@ -68,7 +68,7 @@ public:
if (statusCode != HTTP_STATUS_OK)
throw InternetConnectionError(); //e.g. 404 - HTTP_STATUS_NOT_FOUND
- guardRequest.dismiss();
+ guardRequest .dismiss();
guardInternet.dismiss();
}
@@ -113,10 +113,7 @@ bool canAccessUrl(const wchar_t* url) //throw ()
(void)WinInetAccess(url); //throw InternetConnectionError
return true;
}
- catch (const InternetConnectionError&)
- {
- return false;
- }
+ catch (const InternetConnectionError&) { return false; }
}
diff --git a/ui/custom_grid.cpp b/ui/custom_grid.cpp
index ffa0a9bc..e1e2b5a2 100644
--- a/ui/custom_grid.cpp
+++ b/ui/custom_grid.cpp
@@ -1171,7 +1171,7 @@ private:
toolTip.hide(); //if invalid row...
}
- virtual wxString getToolTip(ColumnType colType) const { return showSyncAction_ ? _("Action") : _("Category"); }
+ virtual wxString getToolTip(ColumnType colType) const { return showSyncAction_ ? _("Action") + L" (F8)" : _("Category") + L" (F8)"; }
bool showSyncAction_;
std::unique_ptr<std::pair<size_t, BlockPosition>> highlight; //(row, block) current mouse highlight
diff --git a/ui/grid_view.cpp b/ui/grid_view.cpp
index dbaff5cd..9a5143c1 100644
--- a/ui/grid_view.cpp
+++ b/ui/grid_view.cpp
@@ -75,7 +75,7 @@ void GridView::updateView(Predicate pred)
//"this->" required by two-pass lookup as enforced by GCC 4.7
//save row position to identify first child *on sorted subview* of DirMapping or BaseDirMapping in case latter are filtered out
- const HierarchyObject* parent = &(fsObj->parent());
+ const HierarchyObject* parent = &fsObj->parent();
for (;;) //map all yet unassociated parents to this row
{
const auto rv = this->rowPositionsFirstChild.insert(std::make_pair(parent, viewRef.size()));
diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp
index 43a14ae3..84d86ceb 100644
--- a/ui/gui_generated.cpp
+++ b/ui/gui_generated.cpp
@@ -133,7 +133,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
m_buttonCompare = new zen::BitmapButton( m_panelTopButtons, wxID_OK, _("Compare"), wxDefaultPosition, wxSize( 180,46 ), 0 );
m_buttonCompare->SetDefault();
m_buttonCompare->SetFont( wxFont( 14, 74, 90, 92, false, wxEmptyString ) );
- m_buttonCompare->SetToolTip( _("Compare both sides") );
+ m_buttonCompare->SetToolTip( _("dummy") );
bSizer30->Add( m_buttonCompare, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -184,11 +184,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
fgSizer12->Add( m_bpButtonSyncConfig, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3 );
- m_buttonStartSync = new zen::BitmapButton( m_panelTopButtons, wxID_ANY, _("Synchronize"), wxDefaultPosition, wxSize( 180,46 ), 0 );
- m_buttonStartSync->SetFont( wxFont( 14, 74, 90, 92, false, wxEmptyString ) );
- m_buttonStartSync->SetToolTip( _("Start synchronization") );
+ m_buttonSync = new zen::BitmapButton( m_panelTopButtons, wxID_ANY, _("Synchronize"), wxDefaultPosition, wxSize( 180,46 ), 0 );
+ m_buttonSync->SetFont( wxFont( 14, 74, 90, 92, false, wxEmptyString ) );
+ m_buttonSync->SetToolTip( _("dummy") );
- fgSizer12->Add( m_buttonStartSync, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ fgSizer12->Add( m_buttonSync, 0, wxALIGN_CENTER_VERTICAL, 5 );
bSizer1551->Add( fgSizer12, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
@@ -386,6 +386,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizer451 = new wxBoxSizer( wxHORIZONTAL );
bSizer451->SetMinSize( wxSize( -1,22 ) );
+ bSizerFileStatus = new wxBoxSizer( wxHORIZONTAL );
+
+ bSizerStatusLeft = new wxBoxSizer( wxHORIZONTAL );
+
wxBoxSizer* bSizer53;
bSizer53 = new wxBoxSizer( wxHORIZONTAL );
@@ -436,25 +440,30 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizer53->Add( 0, 0, 1, wxALIGN_CENTER_VERTICAL, 5 );
- bSizer451->Add( bSizer53, 1, wxALIGN_BOTTOM|wxEXPAND, 5 );
+ bSizerStatusLeft->Add( bSizer53, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_staticline9 = new wxStaticLine( m_panelStatusBar, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
- bSizer451->Add( m_staticline9, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxEXPAND, 2 );
+ bSizerStatusLeft->Add( m_staticline9, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP, 2 );
- bSizer451->Add( 26, 0, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizerFileStatus->Add( bSizerStatusLeft, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ bSizerFileStatus->Add( 26, 0, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticTextStatusMiddle = new wxStaticText( m_panelStatusBar, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextStatusMiddle->Wrap( -1 );
m_staticTextStatusMiddle->SetFont( wxFont( 8, 70, 90, 92, false, wxEmptyString ) );
- bSizer451->Add( m_staticTextStatusMiddle, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizerFileStatus->Add( m_staticTextStatusMiddle, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ bSizerFileStatus->Add( 26, 0, 0, wxALIGN_CENTER_VERTICAL, 5 );
- bSizer451->Add( 26, 0, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizerStatusRight = new wxBoxSizer( wxHORIZONTAL );
m_staticline10 = new wxStaticLine( m_panelStatusBar, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
- bSizer451->Add( m_staticline10, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP, 2 );
+ bSizerStatusRight->Add( m_staticline10, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP, 2 );
wxBoxSizer* bSizer52;
bSizer52 = new wxBoxSizer( wxHORIZONTAL );
@@ -506,7 +515,19 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizer52->Add( 0, 0, 1, wxALIGN_CENTER_VERTICAL, 5 );
- bSizer451->Add( bSizer52, 1, wxALIGN_BOTTOM|wxEXPAND, 5 );
+ bSizerStatusRight->Add( bSizer52, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ bSizerFileStatus->Add( bSizerStatusRight, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ bSizer451->Add( bSizerFileStatus, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+
+ m_staticTextFullStatus = new wxStaticText( m_panelStatusBar, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextFullStatus->Wrap( -1 );
+ m_staticTextFullStatus->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) );
+
+ bSizer451->Add( m_staticTextFullStatus, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_panelStatusBar->SetSizer( bSizer451 );
@@ -526,13 +547,13 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer151;
bSizer151 = new wxBoxSizer( wxHORIZONTAL );
- m_bpButtonLoad = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- m_bpButtonLoad->SetToolTip( _("Open") );
+ m_bpButtonOpen = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ m_bpButtonOpen->SetToolTip( _("dummy") );
- bSizer151->Add( m_bpButtonLoad, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer151->Add( m_bpButtonOpen, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonSave = new wxBitmapButton( m_panelConfig, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- m_bpButtonSave->SetToolTip( _("Save") );
+ m_bpButtonSave->SetToolTip( _("dummy") );
bSizer151->Add( m_bpButtonSave, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -545,7 +566,6 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizerConfig->Add( bSizer151, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
m_listBoxHistory = new wxListBox( m_panelConfig, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_EXTENDED|wxLB_NEEDED_SB|wxLB_SORT );
- m_listBoxHistory->SetToolTip( _("Last used configurations (press DEL to remove from list)") );
m_listBoxHistory->SetMinSize( wxSize( -1,40 ) );
bSizerConfig->Add( m_listBoxHistory, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
@@ -778,47 +798,47 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizerViewFilter->Add( 0, 0, 1, wxEXPAND, 5 );
- m_bpButtonSyncCreateLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowCreateLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncDirOverwLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncDirOverwLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowUpdateLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowUpdateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncDeleteLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncDeleteLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowDeleteLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowDeleteLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonLeftOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowLeftOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowLeftOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonLeftNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowLeftNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowLeftNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonEqual = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonEqual, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowEqual = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowEqual, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonDifferent = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowDifferent = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowDifferent, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncDirNone = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncDirNone, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowDoNothing = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowDoNothing, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonRightNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowRightNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowRightNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonRightOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowRightOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowRightOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncDeleteRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncDeleteRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowDeleteRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowDeleteRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncDirOverwRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncDirOverwRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowUpdateRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonSyncCreateRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonSyncCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowCreateRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonConflict = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
- bSizerViewFilter->Add( m_bpButtonConflict, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ m_bpButtonShowConflict = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW );
+ bSizerViewFilter->Add( m_bpButtonShowConflict, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
bSizerViewFilter->Add( 0, 0, 1, wxEXPAND, 5 );
@@ -850,33 +870,51 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
this->Connect( m_menuItemAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) );
m_buttonCompare->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this );
m_bpButtonCmpConfig->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ), NULL, this );
+ m_bpButtonCmpConfig->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnCompSettingsContext ), NULL, this );
m_bpButtonSyncConfig->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), NULL, this );
- m_buttonStartSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this );
+ m_bpButtonSyncConfig->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnSyncSettingsContext ), NULL, this );
+ m_buttonSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this );
m_bpButtonAddPair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this );
m_bpButtonRemovePair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRemoveTopFolderPair ), NULL, this );
m_bpButtonSwapSides->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapSides ), NULL, this );
- m_bpButtonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
+ m_bpButtonOpen->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
m_bpButtonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ), NULL, this );
m_bpButtonBatchJob->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveAsBatchJob ), NULL, this );
m_listBoxHistory->Connect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnCfgHistoryKeyEvent ), NULL, this );
m_listBoxHistory->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistory ), NULL, this );
m_listBoxHistory->Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistoryDoubleClick ), NULL, this );
+ m_listBoxHistory->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnCfgHistoryRightClick ), NULL, this );
m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this );
+ m_bpButtonFilter->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnGlobalFilterContext ), NULL, this );
m_checkBoxHideExcluded->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnShowExcluded ), NULL, this );
- m_bpButtonSyncCreateLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncCreateLeft ), NULL, this );
- m_bpButtonSyncDirOverwLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirLeft ), NULL, this );
- m_bpButtonSyncDeleteLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDeleteLeft ), NULL, this );
- m_bpButtonLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftOnlyFiles ), NULL, this );
- m_bpButtonLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftNewerFiles ), NULL, this );
- m_bpButtonEqual->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnEqualFiles ), NULL, this );
- m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this );
- m_bpButtonSyncDirNone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), NULL, this );
- m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this );
- m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), NULL, this );
- m_bpButtonSyncDeleteRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDeleteRight ), NULL, this );
- m_bpButtonSyncDirOverwRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirRight ), NULL, this );
- m_bpButtonSyncCreateRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncCreateRight ), NULL, this );
- m_bpButtonConflict->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConflictFiles ), NULL, this );
+ m_bpButtonShowCreateLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowCreateLeft->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowUpdateLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowUpdateLeft->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDeleteLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDeleteLeft->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowLeftOnly->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowLeftNewer->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowEqual->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowEqual->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDifferent->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDoNothing->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDoNothing->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowRightNewer->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowRightOnly->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDeleteRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDeleteRight->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowUpdateRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowUpdateRight->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowCreateRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowCreateRight->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowConflict->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowConflict->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
}
MainDialogGenerated::~MainDialogGenerated()
@@ -898,33 +936,51 @@ MainDialogGenerated::~MainDialogGenerated()
this->Disconnect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) );
m_buttonCompare->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this );
m_bpButtonCmpConfig->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ), NULL, this );
+ m_bpButtonCmpConfig->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnCompSettingsContext ), NULL, this );
m_bpButtonSyncConfig->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), NULL, this );
- m_buttonStartSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this );
+ m_bpButtonSyncConfig->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnSyncSettingsContext ), NULL, this );
+ m_buttonSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this );
m_bpButtonAddPair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this );
m_bpButtonRemovePair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRemoveTopFolderPair ), NULL, this );
m_bpButtonSwapSides->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapSides ), NULL, this );
- m_bpButtonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
+ m_bpButtonOpen->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
m_bpButtonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ), NULL, this );
m_bpButtonBatchJob->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveAsBatchJob ), NULL, this );
m_listBoxHistory->Disconnect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnCfgHistoryKeyEvent ), NULL, this );
m_listBoxHistory->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistory ), NULL, this );
m_listBoxHistory->Disconnect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistoryDoubleClick ), NULL, this );
+ m_listBoxHistory->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnCfgHistoryRightClick ), NULL, this );
m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this );
+ m_bpButtonFilter->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnGlobalFilterContext ), NULL, this );
m_checkBoxHideExcluded->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnShowExcluded ), NULL, this );
- m_bpButtonSyncCreateLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncCreateLeft ), NULL, this );
- m_bpButtonSyncDirOverwLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirLeft ), NULL, this );
- m_bpButtonSyncDeleteLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDeleteLeft ), NULL, this );
- m_bpButtonLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftOnlyFiles ), NULL, this );
- m_bpButtonLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftNewerFiles ), NULL, this );
- m_bpButtonEqual->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnEqualFiles ), NULL, this );
- m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this );
- m_bpButtonSyncDirNone->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), NULL, this );
- m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this );
- m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), NULL, this );
- m_bpButtonSyncDeleteRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDeleteRight ), NULL, this );
- m_bpButtonSyncDirOverwRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirRight ), NULL, this );
- m_bpButtonSyncCreateRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncCreateRight ), NULL, this );
- m_bpButtonConflict->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConflictFiles ), NULL, this );
+ m_bpButtonShowCreateLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowCreateLeft->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowUpdateLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowUpdateLeft->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDeleteLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDeleteLeft->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowLeftOnly->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowLeftNewer->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowEqual->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowEqual->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDifferent->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDoNothing->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDoNothing->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowRightNewer->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowRightOnly->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowDeleteRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowDeleteRight->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowUpdateRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowUpdateRight->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowCreateRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowCreateRight->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
+ m_bpButtonShowConflict->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnToggleViewButton ), NULL, this );
+ m_bpButtonShowConflict->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( MainDialogGenerated::OnViewButtonRightClick ), NULL, this );
}
@@ -2322,7 +2378,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizerCodeInfo = new wxBoxSizer( wxVERTICAL );
- m_staticText72 = new wxStaticText( m_panel33, wxID_ANY, _("Source code written in C++ utilizing:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText72 = new wxStaticText( m_panel33, wxID_ANY, _("Source code written in C++ using:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText72->Wrap( -1 );
m_staticText72->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) );
@@ -2334,35 +2390,30 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer171;
bSizer171 = new wxBoxSizer( wxHORIZONTAL );
- m_hyperlink9 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("MinGW"), wxT("http://www.mingw.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink9->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- bSizer171->Add( m_hyperlink9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
-
m_hyperlink11 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("MS Visual C++"), wxT("http://msdn.microsoft.com/library/60k1461a.aspx"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink11->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
bSizer171->Add( m_hyperlink11, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ m_hyperlink9 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("MinGW"), wxT("http://www.mingw.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink9->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
+ bSizer171->Add( m_hyperlink9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+
m_hyperlink10 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Code::Blocks"), wxT("http://www.codeblocks.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink10->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
bSizer171->Add( m_hyperlink10, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
- m_hyperlink13 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Boost"), wxT("http://www.boost.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink13->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- bSizer171->Add( m_hyperlink13, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
-
m_hyperlink7 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("wxWidgets"), wxT("http://www.wxwidgets.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink7->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
bSizer171->Add( m_hyperlink7, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
- m_hyperlink16 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Artistic Style"), wxT("http://astyle.sourceforge.net"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink16->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+ m_hyperlink14 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("wxFormBuilder"), wxT("http://wxformbuilder.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink14->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
- bSizer171->Add( m_hyperlink16, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer171->Add( m_hyperlink14, 0, wxALIGN_CENTER_VERTICAL, 5 );
bSizer167->Add( bSizer171, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 );
@@ -2370,16 +2421,21 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer172;
bSizer172 = new wxBoxSizer( wxHORIZONTAL );
- m_hyperlink8 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Loki"), wxT("http://loki-lib.sourceforge.net/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- bSizer172->Add( m_hyperlink8, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
-
m_hyperlink15 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("zenXML"), wxT("http://zenxml.sourceforge.net/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink15->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
bSizer172->Add( m_hyperlink15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ m_hyperlink13 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Boost"), wxT("http://www.boost.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink13->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
+ bSizer172->Add( m_hyperlink13, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+
+ m_hyperlink16 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Artistic Style"), wxT("http://astyle.sourceforge.net"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink16->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
+ bSizer172->Add( m_hyperlink16, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+
m_hyperlink12 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Google Test"), wxT("http://code.google.com/p/googletest"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink12->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
@@ -2388,12 +2444,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_hyperlink18 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("Unicode NSIS"), wxT("http://www.scratchpaper.com"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
m_hyperlink18->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
- bSizer172->Add( m_hyperlink18, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
-
- m_hyperlink14 = new wxHyperlinkCtrl( m_panel33, wxID_ANY, _("wxFormBuilder"), wxT("http://wxformbuilder.org"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink14->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- bSizer172->Add( m_hyperlink14, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer172->Add( m_hyperlink18, 0, wxALIGN_CENTER_VERTICAL, 5 );
bSizer167->Add( bSizer172, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
diff --git a/ui/gui_generated.h b/ui/gui_generated.h
index bf93658b..f772f567 100644
--- a/ui/gui_generated.h
+++ b/ui/gui_generated.h
@@ -93,7 +93,7 @@ protected:
wxBitmapButton* m_bpButtonCmpConfig;
wxStaticText* m_staticTextSyncVariant;
wxBitmapButton* m_bpButtonSyncConfig;
- zen::BitmapButton* m_buttonStartSync;
+ zen::BitmapButton* m_buttonSync;
wxPanel* m_panelDirectoryPairs;
wxStaticText* m_staticTextResolvedPathL;
wxBitmapButton* m_bpButtonAddPair;
@@ -111,6 +111,8 @@ protected:
zen::Grid* m_gridMainC;
zen::Grid* m_gridMainR;
wxPanel* m_panelStatusBar;
+ wxBoxSizer* bSizerFileStatus;
+ wxBoxSizer* bSizerStatusLeft;
wxBoxSizer* bSizerStatusLeftDirectories;
wxStaticBitmap* m_bitmapSmallDirectoryLeft;
wxStaticText* m_staticTextStatusLeftDirs;
@@ -120,6 +122,7 @@ protected:
wxStaticText* m_staticTextStatusLeftBytes;
wxStaticLine* m_staticline9;
wxStaticText* m_staticTextStatusMiddle;
+ wxBoxSizer* bSizerStatusRight;
wxStaticLine* m_staticline10;
wxBoxSizer* bSizerStatusRightDirectories;
wxStaticBitmap* m_bitmapSmallDirectoryRight;
@@ -128,9 +131,10 @@ protected:
wxStaticBitmap* m_bitmapSmallFileRight;
wxStaticText* m_staticTextStatusRightFiles;
wxStaticText* m_staticTextStatusRightBytes;
+ wxStaticText* m_staticTextFullStatus;
wxPanel* m_panelConfig;
wxBoxSizer* bSizerConfig;
- wxBitmapButton* m_bpButtonLoad;
+ wxBitmapButton* m_bpButtonOpen;
wxBitmapButton* m_bpButtonSave;
wxBitmapButton* m_bpButtonBatchJob;
wxListBox* m_listBoxHistory;
@@ -155,20 +159,20 @@ protected:
wxStaticText* m_staticTextCreateRight;
wxPanel* m_panelViewFilter;
wxBoxSizer* bSizerViewFilter;
- ToggleButton* m_bpButtonSyncCreateLeft;
- ToggleButton* m_bpButtonSyncDirOverwLeft;
- ToggleButton* m_bpButtonSyncDeleteLeft;
- ToggleButton* m_bpButtonLeftOnly;
- ToggleButton* m_bpButtonLeftNewer;
- ToggleButton* m_bpButtonEqual;
- ToggleButton* m_bpButtonDifferent;
- ToggleButton* m_bpButtonSyncDirNone;
- ToggleButton* m_bpButtonRightNewer;
- ToggleButton* m_bpButtonRightOnly;
- ToggleButton* m_bpButtonSyncDeleteRight;
- ToggleButton* m_bpButtonSyncDirOverwRight;
- ToggleButton* m_bpButtonSyncCreateRight;
- ToggleButton* m_bpButtonConflict;
+ ToggleButton* m_bpButtonShowCreateLeft;
+ ToggleButton* m_bpButtonShowUpdateLeft;
+ ToggleButton* m_bpButtonShowDeleteLeft;
+ ToggleButton* m_bpButtonShowLeftOnly;
+ ToggleButton* m_bpButtonShowLeftNewer;
+ ToggleButton* m_bpButtonShowEqual;
+ ToggleButton* m_bpButtonShowDifferent;
+ ToggleButton* m_bpButtonShowDoNothing;
+ ToggleButton* m_bpButtonShowRightNewer;
+ ToggleButton* m_bpButtonShowRightOnly;
+ ToggleButton* m_bpButtonShowDeleteRight;
+ ToggleButton* m_bpButtonShowUpdateRight;
+ ToggleButton* m_bpButtonShowCreateRight;
+ ToggleButton* m_bpButtonShowConflict;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
@@ -186,29 +190,21 @@ protected:
virtual void OnMenuCheckVersion( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuAbout( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCmpSettings( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnCompSettingsContext( wxMouseEvent& event ) { event.Skip(); }
virtual void OnSyncSettings( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnSyncSettingsContext( wxMouseEvent& event ) { event.Skip(); }
virtual void OnAddFolderPair( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemoveTopFolderPair( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSwapSides( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCfgHistoryKeyEvent( wxKeyEvent& event ) { event.Skip(); }
virtual void OnLoadFromHistory( wxCommandEvent& event ) { event.Skip(); }
virtual void OnLoadFromHistoryDoubleClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnCfgHistoryRightClick( wxMouseEvent& event ) { event.Skip(); }
virtual void OnConfigureFilter( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnGlobalFilterContext( wxMouseEvent& event ) { event.Skip(); }
virtual void OnShowExcluded( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncCreateLeft( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncDirLeft( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncDeleteLeft( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnLeftOnlyFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnLeftNewerFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnEqualFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnDifferentFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncDirNone( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnRightNewerFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnRightOnlyFiles( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncDeleteRight( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncDirRight( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSyncCreateRight( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnConflictFiles( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToggleViewButton( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnViewButtonRightClick( wxMouseEvent& event ) { event.Skip(); }
public:
@@ -594,17 +590,16 @@ protected:
wxPanel* m_panel33;
wxBoxSizer* bSizerCodeInfo;
wxStaticText* m_staticText72;
- wxHyperlinkCtrl* m_hyperlink9;
wxHyperlinkCtrl* m_hyperlink11;
+ wxHyperlinkCtrl* m_hyperlink9;
wxHyperlinkCtrl* m_hyperlink10;
- wxHyperlinkCtrl* m_hyperlink13;
wxHyperlinkCtrl* m_hyperlink7;
- wxHyperlinkCtrl* m_hyperlink16;
- wxHyperlinkCtrl* m_hyperlink8;
+ wxHyperlinkCtrl* m_hyperlink14;
wxHyperlinkCtrl* m_hyperlink15;
+ wxHyperlinkCtrl* m_hyperlink13;
+ wxHyperlinkCtrl* m_hyperlink16;
wxHyperlinkCtrl* m_hyperlink12;
wxHyperlinkCtrl* m_hyperlink18;
- wxHyperlinkCtrl* m_hyperlink14;
wxHyperlinkCtrl* m_hyperlink21;
wxPanel* m_panel40;
wxPanel* m_panel39;
diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp
index 0f915ed9..5d3a1f36 100644
--- a/ui/gui_status_handler.cpp
+++ b/ui/gui_status_handler.cpp
@@ -250,7 +250,7 @@ SyncStatusHandler::~SyncStatusHandler()
showFinalResults = false; //take precedence over current visibility status
else if (!finalCommand.empty())
{
- auto cmdexp = utfCvrtTo<wxString>(expandMacros(utfCvrtTo<Zstring>(finalCommand)));
+ auto cmdexp = expandMacros(utfCvrtTo<Zstring>(finalCommand));
shellExecute(cmdexp);
}
}
@@ -283,7 +283,7 @@ void SyncStatusHandler::initNewPhase(int objectsTotal, Int64 dataTotal, Phase ph
void SyncStatusHandler::updateProcessedData(int objectsDelta, Int64 dataDelta)
{
StatusHandler::updateProcessedData(objectsDelta, dataDelta);
- syncStatusFrame.reportCurrentBytes(getDataCurrent(currentPhase())); //throw ()
+ syncStatusFrame.notifyProgressChange(); //noexcept
//note: this method should NOT throw in order to properly allow undoing setting of statistics!
}
@@ -410,7 +410,7 @@ void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
void SyncStatusHandler::forceUiRefresh()
{
- syncStatusFrame.updateProgress();
+ syncStatusFrame.updateGui();
}
diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp
index c3f33db5..cae45cd1 100644
--- a/ui/main_dlg.cpp
+++ b/ui/main_dlg.cpp
@@ -5,57 +5,44 @@
// **************************************************************************
#include "main_dlg.h"
-#include <iterator>
-#include <stdexcept>
#include <wx/clipbrd.h>
-#include <wx/dataobj.h>
-#include <wx/imaglist.h>
#include <wx/wupdlock.h>
#include <wx/msgdlg.h>
#include <wx/sound.h>
-#include <wx/display.h>
-#include <wx/app.h>
-#include <wx/dcmemory.h>
#include <wx/filedlg.h>
#include <zen/format_unit.h>
+#include <zen/file_handling.h>
+#include <zen/serialize.h>
+#include <zen/file_id.h>
+#include <zen/thread.h>
#include <wx+/context_menu.h>
-#include "folder_history_box.h"
#include <wx+/button.h>
-#include "../comparison.h"
-#include "../synchronization.h"
-#include "../algorithm.h"
+#include <wx+/shell_execute.h>
#include <wx+/app_main.h>
+#include <wx+/toggle_button.h>
+#include <wx+/mouse_move_dlg.h>
+#include <wx+/no_flicker.h>
+#include <wx+/rtl.h>
#include "check_version.h"
#include "gui_status_handler.h"
#include "sync_cfg.h"
#include "small_dlgs.h"
-#include <wx+/mouse_move_dlg.h>
#include "progress_indicator.h"
#include "msg_popup.h"
-#include "../structures.h"
-#include "grid_view.h"
+#include "folder_pair.h"
+#include "search.h"
+#include "batch_config.h"
+#include "triple_splitter.h"
+#include "../comparison.h"
+#include "../synchronization.h"
+#include "../algorithm.h"
#include "../lib/resources.h"
-#include <zen/file_handling.h>
-#include <zen/serialize.h>
-#include <zen/file_id.h>
-#include <zen/recycler.h>
#include "../lib/resolve_path.h"
#include "../lib/ffs_paths.h"
-#include <wx+/toggle_button.h>
-#include "folder_pair.h"
-#include <wx+/rtl.h>
-#include "search.h"
#include "../lib/help_provider.h"
-#include "batch_config.h"
-#include <zen/thread.h>
#include "../lib/lock_holder.h"
-#include <wx+/shell_execute.h>
#include "../lib/localization.h"
-#include <wx+/image_tools.h>
-#include <wx+/no_flicker.h>
-#include <wx+/grid.h>
-#include "../lib/error_log.h"
-#include "triple_splitter.h"
+#include <zen/perf.h>
using namespace zen;
using namespace std::rel_ops;
@@ -281,12 +268,13 @@ public:
virtual bool allowMove(const wxMouseEvent& event)
{
- wxPanel* panel = dynamic_cast<wxPanel*>(event.GetEventObject());
-
- const wxAuiPaneInfo& paneInfo = mainDlg_.auiMgr.GetPane(panel);
- if (paneInfo.IsOk() &&
- paneInfo.IsFloating())
- return false; //prevent main dialog move
+ if (wxPanel* panel = dynamic_cast<wxPanel*>(event.GetEventObject()))
+ {
+ const wxAuiPaneInfo& paneInfo = mainDlg_.auiMgr.GetPane(panel);
+ if (paneInfo.IsOk() &&
+ paneInfo.IsFloating())
+ return false; //prevent main dialog move
+ }
return true; //allow dialog move
}
@@ -507,7 +495,7 @@ MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg,
wxAuiPaneInfo().Name(wxT("Panel5")).Layer(4).Bottom().Row(1).Position(1).Caption(_("Filter files")).MinSize(m_bpButtonFilter->GetSize().GetWidth(), m_panelFilter->GetSize().GetHeight()));
auiMgr.AddPane(m_panelViewFilter,
- wxAuiPaneInfo().Name(wxT("Panel6")).Layer(4).Bottom().Row(1).Position(2).Caption(_("Select view")).MinSize(m_bpButtonSyncDirNone->GetSize().GetWidth(), m_panelViewFilter->GetSize().GetHeight()));
+ wxAuiPaneInfo().Name(wxT("Panel6")).Layer(4).Bottom().Row(1).Position(2).Caption(_("Select view")).MinSize(m_bpButtonShowDoNothing->GetSize().GetWidth(), m_panelViewFilter->GetSize().GetHeight()));
auiMgr.AddPane(m_panelStatistics,
wxAuiPaneInfo().Name(wxT("Panel7")).Layer(4).Bottom().Row(1).Position(3).Caption(_("Statistics")).MinSize(m_bitmapData->GetSize().GetWidth() + m_staticTextData->GetSize().GetWidth(), m_panelStatistics->GetSize().GetHeight()));
@@ -536,19 +524,14 @@ MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg,
m_panelStatusBar ->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainDialog::OnContextSetLayout), nullptr, this);
//----------------------------------------------------------------------------------
- //register context: quick variant selection
- m_bpButtonCmpConfig ->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (MainDialog::OnCompSettingsContext), nullptr, this);
- m_bpButtonSyncConfig->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (MainDialog::OnSyncSettingsContext), nullptr, this);
- m_bpButtonFilter ->Connect(wxEVT_RIGHT_DOWN, wxCommandEventHandler(MainDialog::OnGlobalFilterContext), nullptr, this);
-
//sort grids
- m_gridMainL->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickL ), nullptr, this );
- m_gridMainC->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickC ), nullptr, this );
- m_gridMainR->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickR ), nullptr, this );
+ m_gridMainL->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickL ), nullptr, this);
+ m_gridMainC->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickC ), nullptr, this);
+ m_gridMainR->Connect(EVENT_GRID_COL_LABEL_MOUSE_LEFT, GridClickEventHandler(MainDialog::onGridLabelLeftClickR ), nullptr, this);
- m_gridMainL->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextL ), nullptr, this );
- m_gridMainC->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextC ), nullptr, this );
- m_gridMainR->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextR ), nullptr, this );
+ m_gridMainL->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextL ), nullptr, this);
+ m_gridMainC->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextC ), nullptr, this);
+ m_gridMainR->Connect(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, GridClickEventHandler(MainDialog::onGridLabelContextR ), nullptr, this);
//grid context menu
m_gridMainL->Connect(EVENT_GRID_MOUSE_RIGHT_UP, GridClickEventHandler(MainDialog::onMainGridContextL), nullptr, this);
@@ -561,8 +544,14 @@ MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg,
m_gridNavi->Connect(EVENT_GRID_SELECT_RANGE, GridRangeSelectEventHandler(MainDialog::onNaviSelection), nullptr, this);
- gridDataView.reset(new zen::GridView);
- treeDataView.reset(new zen::TreeView);
+ //set tool tips with (non-translated!) short cut hint
+ m_bpButtonOpen ->SetToolTip(_("Open...") + L" (Ctrl+O)");
+ m_bpButtonSave ->SetToolTip(_("Save") + L" (Ctrl+S)");
+ m_buttonCompare->SetToolTip(_("Compare both sides") + L" (F5)");
+ m_buttonSync ->SetToolTip(_("Start synchronization") + L" (F6)");
+
+ gridDataView = std::make_shared<GridView>();
+ treeDataView = std::make_shared<TreeView>();
cleanedUp = false;
processingGlobalKeyEvent = false;
@@ -579,7 +568,7 @@ MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg,
//init handling of first folder pair
firstFolderPair.reset(new DirectoryPairFirst(*this));
- //initViewFilterButtons();
+ initViewFilterButtons();
//init grid settings
gridview::init(*m_gridMainL, *m_gridMainC, *m_gridMainR, gridDataView);
@@ -593,7 +582,7 @@ MainDialog::MainDialog(const xmlAccess::XmlGuiConfig& guiCfg,
m_buttonCompare ->setBitmapFront(GlobalResources::getImage(L"compare"), 5);
m_bpButtonSyncConfig->SetBitmapLabel(GlobalResources::getImage(L"syncConfig"));
m_bpButtonCmpConfig ->SetBitmapLabel(GlobalResources::getImage(L"cmpConfig"));
- m_bpButtonLoad ->SetBitmapLabel(GlobalResources::getImage(L"load"));
+ m_bpButtonOpen ->SetBitmapLabel(GlobalResources::getImage(L"load"));
m_bpButtonBatchJob ->SetBitmapLabel(GlobalResources::getImage(L"batch"));
m_bpButtonAddPair ->SetBitmapLabel(GlobalResources::getImage(L"item_add"));
@@ -1060,29 +1049,28 @@ std::vector<FileSystemObject*> MainDialog::getTreeSelection() const
//Exception class used to abort the "compare" and "sync" process
class AbortDeleteProcess {};
-class ManualDeletionHandler : private wxEvtHandler, public DeleteFilesHandler
+class ManualDeletionHandler : private wxEvtHandler, public DeleteFilesHandler //throw AbortDeleteProcess
{
public:
- ManualDeletionHandler(MainDialog* main) :
+ ManualDeletionHandler(MainDialog& main) :
mainDlg(main),
abortRequested(false),
- ignoreErrors(false),
- deletionCount(0)
+ ignoreErrors(false)
{
- mainDlg->disableAllElements(true); //disable everything except abort button
+ mainDlg.disableAllElements(true); //disable everything except abort button
//register abort button
- mainDlg->m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ManualDeletionHandler::OnAbortDeletion), nullptr, this );
- mainDlg->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(ManualDeletionHandler::OnKeyPressed), nullptr, this);
+ mainDlg.m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ManualDeletionHandler::OnAbortDeletion), nullptr, this );
+ mainDlg.Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(ManualDeletionHandler::OnKeyPressed), nullptr, this);
}
~ManualDeletionHandler()
{
//de-register abort button
- mainDlg->Disconnect(wxEVT_CHAR_HOOK, wxKeyEventHandler(ManualDeletionHandler::OnKeyPressed), nullptr, this);
- mainDlg->m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ManualDeletionHandler::OnAbortDeletion ), nullptr, this );
+ mainDlg.Disconnect(wxEVT_CHAR_HOOK, wxKeyEventHandler(ManualDeletionHandler::OnKeyPressed), nullptr, this);
+ mainDlg.m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ManualDeletionHandler::OnAbortDeletion ), nullptr, this );
- mainDlg->enableAllElements();
+ mainDlg.enableAllElements();
}
virtual Response reportError(const std::wstring& msg)
@@ -1090,9 +1078,9 @@ public:
if (ignoreErrors)
return DeleteFilesHandler::IGNORE_ERROR;
- updateGUI();
+ forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(mainDlg,
+ switch (showErrorDlg(&mainDlg,
ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL,
msg, &ignoreNextErrors))
{
@@ -1114,9 +1102,9 @@ public:
if (!warningActive || ignoreErrors)
return;
- updateGUI();
+ forceUiRefresh();
bool dontWarnAgain = false;
- switch (showWarningDlg(mainDlg, ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_CANCEL, msg, dontWarnAgain))
+ switch (showWarningDlg(&mainDlg, ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_CANCEL, msg, dontWarnAgain))
{
case ReturnWarningDlg::BUTTON_SWITCH:
assert(false);
@@ -1129,26 +1117,29 @@ public:
}
}
- virtual void notifyDeletion(const Zstring& currentObject) //called for each file/folder that has been deleted
+ virtual void reportStatus (const std::wstring& msg)
{
- ++deletionCount;
- updateGUI();
+ statusMsg = msg;
+ requestUiRefresh();
}
private:
- void updateGUI()
+ virtual void requestUiRefresh()
{
if (updateUiIsAllowed()) //test if specific time span between ui updates is over
- {
- mainDlg->setStatusInformation(replaceCpy(_P("Object deleted successfully!", "%x objects deleted successfully!", deletionCount),
- L"%x", zen::toGuiString(deletionCount), false));
- updateUiNow();
- }
+ forceUiRefresh();
if (abortRequested) //test after (implicit) call to wxApp::Yield()
throw AbortDeleteProcess();
}
+ void forceUiRefresh()
+ {
+ //std::wstring msg = toGuiString(deletionCount) +
+ mainDlg.setStatusBarFullText(statusMsg);
+ updateUiNow();
+ }
+
//context: C callstack message loop => throw()!
void OnAbortDeletion(wxCommandEvent& event) //handle abort button click
{
@@ -1167,11 +1158,12 @@ private:
event.Skip();
}
- MainDialog* const mainDlg;
+ MainDialog& mainDlg;
bool abortRequested;
bool ignoreErrors;
- size_t deletionCount;
+ //size_t deletionCount; //
+ std::wstring statusMsg; //status reporting
};
@@ -1180,184 +1172,223 @@ void MainDialog::deleteSelectedFiles(const std::vector<FileSystemObject*>& selec
{
if (!selectionLeft.empty() || !selectionRight.empty())
{
+ wxBusyCursor dummy; //show hourglass cursor
+
wxWindow* oldFocus = wxWindow::FindFocus();
ZEN_ON_SCOPE_EXIT(if (oldFocus) oldFocus->SetFocus();)
- if (zen::showDeleteDialog(this,
- selectionLeft,
- selectionRight,
- globalCfg.gui.deleteOnBothSides,
- globalCfg.gui.useRecyclerForManualDeletion) == ReturnSmallDlg::BUTTON_OKAY)
+ bool deleteOnBothSides = false; //let's keep this disabled by default -> don't save
+
+ if (zen::showDeleteDialog(this,
+ selectionLeft,
+ selectionRight,
+ deleteOnBothSides,
+ globalCfg.gui.useRecyclerForManualDeletion) == ReturnSmallDlg::BUTTON_OKAY)
+ {
+ try
{
- try
- {
- //handle errors when deleting files/folders
- ManualDeletionHandler statusHandler(this);
-
- zen::deleteFromGridAndHD(selectionLeft,
- selectionRight,
- folderCmp,
- extractDirectionCfg(getConfig().mainCfg),
- globalCfg.gui.deleteOnBothSides,
- globalCfg.gui.useRecyclerForManualDeletion,
- statusHandler,
- globalCfg.optDialogs.warningRecyclerMissing);
-
- gridview::clearSelection(*m_gridMainL, *m_gridMainC, *m_gridMainR); //do not clear, if aborted!
- }
- catch (AbortDeleteProcess&) {}
+ //handle errors when deleting files/folders
+ ManualDeletionHandler statusHandler(*this);
+
+ zen::deleteFromGridAndHD(selectionLeft,
+ selectionRight,
+ folderCmp,
+ extractDirectionCfg(getConfig().mainCfg),
+ deleteOnBothSides,
+ globalCfg.gui.useRecyclerForManualDeletion,
+ statusHandler,
+ globalCfg.optDialogs.warningRecyclerMissing);
+
+ gridview::clearSelection(*m_gridMainL, *m_gridMainC, *m_gridMainR); //do not clear, if aborted!
+ }
+ catch (AbortDeleteProcess&) {}
- //remove rows that are empty: just a beautification, invalid rows shouldn't cause issues
- gridDataView->removeInvalidRows();
+ //remove rows that are empty: just a beautification, invalid rows shouldn't cause issues
+ gridDataView->removeInvalidRows();
- //redraw grid neccessary to update new dimensions and for UI-Backend data linkage
- updateGui(); //call immediately after deleteFromGridAndHD!!!
- }
+ //redraw grid neccessary to update new dimensions and for UI-Backend data linkage
+ updateGui(); //call immediately after deleteFromGridAndHD!!!
+ }
}
}
-
+namespace
+{
template <SelectedSide side>
-wxString extractLastValidDir(const FileSystemObject& fsObj)
+Zstring getExistingParentFolder(const FileSystemObject& fsObj)
{
- Zstring fullname = fsObj.getBaseDirPf<side>() + fsObj.getObjRelativeName(); //full name even if FileSystemObject::isEmpty<side>() == true
+ const DirMapping* dirObj = dynamic_cast<const DirMapping*>(&fsObj);
+ if (!dirObj)
+ dirObj = dynamic_cast<const DirMapping*>(&fsObj.parent());
- while (!fullname.empty() && !dirExists(fullname)) //bad algorithm: this one should better retrieve the status from fsObj
- fullname = beforeLast(fullname, FILE_NAME_SEPARATOR);
+ while (dirObj)
+ {
+ if (!dirObj->isEmpty<side>())
+ return dirObj->getFullName<side>();
- return toWx(fullname);
+ dirObj = dynamic_cast<const DirMapping*>(&dirObj->parent());
+ }
+ return fsObj.getBaseDirPf<side>();
+}
}
-
-void MainDialog::openExternalApplication(const wxString& commandline, const zen::FileSystemObject* fsObj, bool leftSide) //fsObj may be nullptr
+void MainDialog::openExternalApplication(const wxString& commandline, const std::vector<FileSystemObject*>& selection, bool leftSide)
{
if (commandline.empty())
return;
- wxString name;
- wxString nameCo;
- wxString dir;
- wxString dirCo;
+ auto selectionTmp = selection;
- if (fsObj)
+ const bool openFileBrowserRequested = [&]() -> bool
{
- name = toWx(fsObj->getFullName<LEFT_SIDE>()); //empty if obj not existing
- dir = toWx(beforeLast(fsObj->getFullName<LEFT_SIDE>(), FILE_NAME_SEPARATOR)); //small issue: if obj does not exist but parent exists, this one erronously returns empty
+ xmlAccess::XmlGlobalSettings::Gui dummy;
+ return !dummy.externelApplications.empty() && dummy.externelApplications[0].second == commandline;
+ }();
- nameCo = toWx(fsObj->getFullName<RIGHT_SIDE>());
- dirCo = toWx(beforeLast(fsObj->getFullName<RIGHT_SIDE>(), FILE_NAME_SEPARATOR));
+ //support fallback instead of an error in this special case
+ if (openFileBrowserRequested)
+ {
+ if (selectionTmp.size() > 1) //do not open more than one explorer instance!
+ selectionTmp.resize(1); //
+
+ if (selectionTmp.empty() ||
+ (leftSide && selectionTmp[0]->isEmpty<LEFT_SIDE >()) ||
+ (!leftSide && selectionTmp[0]->isEmpty<RIGHT_SIDE>()))
+ {
+ Zstring fallbackDir;
+ if (selectionTmp.empty())
+ fallbackDir = leftSide ?
+ getFormattedDirectoryName(toZ(firstFolderPair->getLeftDir())) :
+ getFormattedDirectoryName(toZ(firstFolderPair->getRightDir()));
+
+ else
+ fallbackDir = leftSide ?
+ getExistingParentFolder<LEFT_SIDE >(*selectionTmp[0]) :
+ getExistingParentFolder<RIGHT_SIDE>(*selectionTmp[0]);
+#ifdef FFS_WIN
+ zen::shellExecute(L"\"" + fallbackDir + L"\"");
+#elif defined FFS_LINUX
+ zen::shellExecute("xdg-open \"" + fallbackDir + "\"");
+#endif
+ return;
+ }
}
- if (!leftSide)
+ //regular command evaluation
+ for (auto it = selectionTmp.begin(); it != selectionTmp.end(); ++it) //context menu calls this function only if selection is not empty!
{
- std::swap(name, nameCo);
- std::swap(dir, dirCo);
- }
+ const FileSystemObject* fsObj = *it;
- wxString command = commandline;
+ Zstring path1 = fsObj->getBaseDirPf<LEFT_SIDE>() + fsObj->getObjRelativeName(); //full path, even if item is not existing!
+ Zstring dir1 = beforeLast(path1, FILE_NAME_SEPARATOR); //Win: wrong for root paths like "C:\file.txt"
- auto tryReplace = [&](wxString phrase, const wxString& replacement) -> bool
- {
- wxString cmdTmp = command.Upper(); //case insensitive search
- phrase.MakeUpper(); //
+ Zstring path2 = fsObj->getBaseDirPf<RIGHT_SIDE>() + fsObj->getObjRelativeName();
+ Zstring dir2 = beforeLast(path2, FILE_NAME_SEPARATOR);
- size_t pos = cmdTmp.find(phrase);
- if (pos != wxString::npos)
+ if (!leftSide)
{
- command.replace(pos, phrase.size(), replacement);
- if (replacement.empty())
- return false;
+ std::swap(path1, path2);
+ std::swap(dir1, dir2);
}
- return true;
- };
- bool expandSuccess =
- /**/ tryReplace(L"%item_path%" , name ); //prevent short-cut behavior!
- expandSuccess = tryReplace(L"%item_folder%" , dir ) && expandSuccess; //
- expandSuccess = tryReplace(L"%item2_path%" , nameCo) && expandSuccess; //
- expandSuccess = tryReplace(L"%item2_folder%", dirCo ) && expandSuccess; //
+ Zstring command = utfCvrtTo<Zstring>(commandline);
+ replace(command, Zstr("%item_path%"), path1);
+ replace(command, Zstr("%item2_path%"), path2);
+ replace(command, Zstr("%item_folder%"), dir1 );
+ replace(command, Zstr("%item2_folder%"), dir2 );
- const bool openFileBrowser = [&]() -> bool
- {
- xmlAccess::XmlGlobalSettings::Gui dummy;
- return !dummy.externelApplications.empty() && dummy.externelApplications[0].second == commandline;
- }();
+ auto cmdExp = expandMacros(command);
+ zen::shellExecute(cmdExp); //shows error message if command is malformed
+ }
+}
- if (!openFileBrowser || expandSuccess)
+
+void MainDialog::setStatusBarFileStatistics(size_t filesOnLeftView,
+ size_t foldersOnLeftView,
+ size_t filesOnRightView,
+ size_t foldersOnRightView,
+ UInt64 filesizeLeftView,
+ UInt64 filesizeRightView)
+{
+ wxWindowUpdateLocker dummy(m_panelStatusBar); //avoid display distortion
+
+ //select state
+ bSizerFileStatus->Show(true);
+ m_staticTextFullStatus->Hide();
+
+ //fill statistics
+ //update status information
+ bSizerStatusLeftDirectories->Show(foldersOnLeftView > 0);
+ bSizerStatusLeftFiles ->Show(filesOnLeftView > 0);
+
+ setText(*m_staticTextStatusLeftDirs, replaceCpy(_P("1 directory", "%x directories", foldersOnLeftView), L"%x", toGuiString(foldersOnLeftView), false));
+ setText(*m_staticTextStatusLeftFiles, replaceCpy(_P("1 file", "%x files", filesOnLeftView), L"%x", toGuiString(filesOnLeftView), false));
+ setText(*m_staticTextStatusLeftBytes, filesizeToShortString(to<Int64>(filesizeLeftView)));
+
+ wxString statusMiddleNew;
+ if (gridDataView->rowsTotal() > 0)
{
- auto cmdExp = utfCvrtTo<wxString>(expandMacros(utfCvrtTo<Zstring>(command)));
- zen::shellExecute(cmdExp); //just execute, show error message if command is malformed
+ statusMiddleNew = _P("%x of 1 row in view", "%x of %y rows in view", gridDataView->rowsTotal());
+ replace(statusMiddleNew, L"%x", toGuiString(gridDataView->rowsOnView()), false);
+ replace(statusMiddleNew, L"%y", toGuiString(gridDataView->rowsTotal ()), false);
}
- else //failed to expand file browser command: support built-in fallback instead of an error!
- {
- wxString fallbackDir;
- if (fsObj)
- fallbackDir = leftSide ?
- extractLastValidDir<LEFT_SIDE >(*fsObj) :
- extractLastValidDir<RIGHT_SIDE>(*fsObj);
- if (fallbackDir.empty())
- fallbackDir = leftSide ?
- toWx(zen::getFormattedDirectoryName(toZ(firstFolderPair->getLeftDir()))) :
- toWx(zen::getFormattedDirectoryName(toZ(firstFolderPair->getRightDir())));
+ bSizerStatusRightDirectories->Show(foldersOnRightView > 0);
+ bSizerStatusRightFiles ->Show(filesOnRightView > 0);
-#ifdef FFS_WIN
- zen::shellExecute(wxString(L"\"") + fallbackDir + L"\"");
-#elif defined FFS_LINUX
- zen::shellExecute(wxString(L"xdg-open \"") + fallbackDir + L"\"");
-#endif
- }
+ setText(*m_staticTextStatusRightDirs, replaceCpy(_P("1 directory", "%x directories", foldersOnRightView), L"%x", toGuiString(foldersOnRightView), false));
+ setText(*m_staticTextStatusRightFiles, replaceCpy(_P("1 file", "%x files", filesOnRightView), L"%x", toGuiString(filesOnRightView), false));
+ setText(*m_staticTextStatusRightBytes, filesizeToShortString(to<Int64>(filesizeRightView)));
+
+
+ //fill middle text (considering flashStatusInformation())
+ if (!oldStatusMsg)
+ setText(*m_staticTextStatusMiddle, statusMiddleNew);
+ else
+ *oldStatusMsg = statusMiddleNew;
+
+ m_panelStatusBar->Layout();
}
-void MainDialog::setStatusInformation(const wxString& msg)
+void MainDialog::setStatusBarFullText(const wxString& msg)
{
- if (statusMsgStack.empty())
- {
- if (m_staticTextStatusMiddle->GetLabel() != msg)
- {
- m_staticTextStatusMiddle->SetLabel(msg);
- m_panelStatusBar->Layout();
- }
- }
- else
- statusMsgStack[0] = msg; //statusMsgStack, index 0 is main status, while 1, 2, ... are temporary status texts in reverse order of screen appearance
+ //select state
+ bSizerFileStatus->Show(false);
+ m_staticTextFullStatus->Show();
+
+ //update status information
+ setText(*m_staticTextFullStatus, msg);
+ m_panelStatusBar->Layout();
}
void MainDialog::flashStatusInformation(const wxString& text)
{
- if (statusMsgStack.empty())
- {
- statusMsgStack.push_back(m_staticTextStatusMiddle->GetLabel());
+ if (!oldStatusMsg)
+ oldStatusMsg = make_unique<wxString>(m_staticTextStatusMiddle->GetLabel());
- lastStatusChange = wxGetLocalTimeMillis();
- m_staticTextStatusMiddle->SetLabel(text);
- m_staticTextStatusMiddle->SetForegroundColour(wxColour(31, 57, 226)); //highlight color: blue
- m_panelStatusBar->Layout();
- }
- else
- statusMsgStack.insert(statusMsgStack.begin() + 1, text);
+ lastStatusChange = wxGetLocalTimeMillis();
+ m_staticTextStatusMiddle->SetLabel(text);
+ m_staticTextStatusMiddle->SetForegroundColour(wxColour(31, 57, 226)); //highlight color: blue
+ m_panelStatusBar->Layout();
}
void MainDialog::OnIdleEvent(wxEvent& event)
{
//small routine to restore status information after some time
- if (!statusMsgStack.empty()) //check if there is some work to do
+ if (oldStatusMsg) //check if there is some work to do
{
wxMilliClock_t currentTime = wxGetLocalTimeMillis();
- if (currentTime - lastStatusChange > 2500) //restore stackObject after two seconds
+ if (numeric::dist(currentTime, lastStatusChange) > 2500) //restore stackObject after two seconds
{
lastStatusChange = currentTime;
- m_staticTextStatusMiddle->SetLabel(statusMsgStack.back());
- statusMsgStack.pop_back();
-
- if (statusMsgStack.empty())
- m_staticTextStatusMiddle->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //reset color
-
+ m_staticTextStatusMiddle->SetLabel(*oldStatusMsg);
+ m_staticTextStatusMiddle->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //reset color
m_panelStatusBar->Layout();
+ oldStatusMsg.reset();
}
}
@@ -1367,7 +1398,7 @@ void MainDialog::OnIdleEvent(wxEvent& event)
void MainDialog::disableAllElements(bool enableAbort)
{
- //when changing consider: comparison, synchronization, manual deletion
+ //when changing consider: comparison, synchronization, manual deletion
EnableCloseButton(false); //not allowed for synchronization! progress indicator is top window!
@@ -1377,13 +1408,14 @@ void MainDialog::disableAllElements(bool enableAbort)
m_panelFilter ->Disable();
m_panelConfig ->Disable();
m_bpButtonSyncConfig ->Disable();
- m_buttonStartSync ->Disable();
+ m_buttonSync ->Disable();
m_gridMainL ->Disable();
m_gridMainC ->Disable();
m_gridMainR ->Disable();
m_panelStatistics ->Disable();
m_gridNavi ->Disable();
m_panelDirectoryPairs->Disable();
+ m_splitterMain ->Disable();
m_menubar1->EnableTop(0, false);
m_menubar1->EnableTop(1, false);
m_menubar1->EnableTop(2, false);
@@ -1415,13 +1447,14 @@ void MainDialog::enableAllElements()
m_panelFilter ->Enable();
m_panelConfig ->Enable();
m_bpButtonSyncConfig ->Enable();
- m_buttonStartSync ->Enable();
+ m_buttonSync ->Enable();
m_gridMainL ->Enable();
m_gridMainC ->Enable();
m_gridMainR ->Enable();
m_panelStatistics ->Enable();
m_gridNavi ->Enable();
m_panelDirectoryPairs->Enable();
+ m_splitterMain ->Enable();
m_menubar1->EnableTop(0, true);
m_menubar1->EnableTop(1, true);
m_menubar1->EnableTop(2, true);
@@ -1643,12 +1676,8 @@ void MainDialog::onGridButtonEvent(wxKeyEvent& event, Grid& grid, bool leftSide)
case WXK_RETURN:
case WXK_NUMPAD_ENTER:
if (!globalCfg.gui.externelApplications.empty())
- {
- const wxString commandline = globalCfg.gui.externelApplications[0].second; //open with first external application
- auto cursorPos = grid.getGridCursor();
- const size_t row = cursorPos.first;
- openExternalApplication(commandline, gridDataView->getObject(row), leftSide);
- }
+ openExternalApplication(globalCfg.gui.externelApplications[0].second, //open with first external application
+ getGridSelection(), leftSide);
return;
}
@@ -1832,7 +1861,7 @@ void MainDialog::onNaviGridContext(GridClickEvent& event)
std::swap(shortCutLeft, shortCutRight);
menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_RIGHT); }, &opRight);
- menu.addItem(_("Set direction:") + L" -" L"\tAlt+Up", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone);
+ menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone);
menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_LEFT); }, &opLeft);
//Gtk needs a direction, "<-", because it has no context menu icons!
//Gtk requires "no spaces" for shortcut identifiers!
@@ -1867,7 +1896,7 @@ void MainDialog::onNaviGridContext(GridClickEvent& event)
//----------------------------------------------------------------------------------------------------
//CONTEXT_DELETE_FILES
menu.addSeparator();
- menu.addItem(_("Delete") + L"\tDel", [&] { deleteSelectedFiles(selection, selection); }, nullptr, !selection.empty());
+ menu.addItem(_("Delete") + L"\tDelete", [&] { deleteSelectedFiles(selection, selection); }, nullptr, !selection.empty());
menu.popup(*this);
}
@@ -1924,7 +1953,7 @@ void MainDialog::onMainGridContextRim(bool leftSide)
std::swap(shortCutLeft, shortCutRight);
menu.addItem(_("Set direction:") + L" ->" + shortCutRight, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_RIGHT); }, &opRight);
- menu.addItem(_("Set direction:") + L" -" L"\tAlt+Up", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone);
+ menu.addItem(_("Set direction:") + L" -" L"\tAlt+Down", [this, &selection] { setSyncDirManually(selection, SYNC_DIR_NONE); }, &opNone);
menu.addItem(_("Set direction:") + L" <-" + shortCutLeft, [this, &selection] { setSyncDirManually(selection, SYNC_DIR_LEFT); }, &opLeft);
//Gtk needs a direction, "<-", because it has no context menu icons!
//Gtk requires "no spaces" for shortcut identifiers!
@@ -1987,26 +2016,26 @@ void MainDialog::onMainGridContextRim(bool leftSide)
it != globalCfg.gui.externelApplications.end();
++it)
{
- //some trick to translate default external apps on the fly: 1. "open in explorer" 2. "start directly"
+ //translate default external apps on the fly: 1. "open in explorer" 2. "start directly"
wxString description = zen::implementation::translate(it->first);
if (description.empty())
description = L" "; //wxWidgets doesn't like empty items
- const wxString command = it->second;
+ const wxString command = it->second; //COPY into lambda
- auto openApp = [this, &selection, leftSide, command] { openExternalApplication(command, selection.empty() ? nullptr : selection[0], leftSide); };
+ auto openApp = [this, &selection, leftSide, command] { openExternalApplication(command, selection, leftSide); };
if (it == globalCfg.gui.externelApplications.begin())
- menu.addItem(description + L"\tEnter", openApp);
- else
- menu.addItem(description, openApp, nullptr, !selection.empty());
+ description += L"\tEnter";
+
+ menu.addItem(description, openApp, nullptr, !selection.empty());
}
}
//----------------------------------------------------------------------------------------------------
//CONTEXT_DELETE_FILES
menu.addSeparator();
- menu.addItem(_("Delete") + L"\tDel", [this]
+ menu.addItem(_("Delete") + L"\tDelete", [this]
{
deleteSelectedFiles(
getGridSelection(true, false),
@@ -2724,38 +2753,48 @@ bool MainDialog::loadConfiguration(const std::vector<wxString>& filenames)
}
}
-
-void MainDialog::OnCfgHistoryKeyEvent(wxKeyEvent& event)
+void MainDialog::deleteSelectedCfgHistoryItems()
{
- const int keyCode = event.GetKeyCode();
- if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE)
+ wxArrayInt tmp;
+ m_listBoxHistory->GetSelections(tmp);
+
+ std::set<int> selections(tmp.begin(), tmp.end()); //sort ascending!
+
+ int shift = 0;
+ std::for_each(selections.begin(), selections.end(),
+ [&](int pos)
+ {
+ m_listBoxHistory->Delete(pos + shift);
+ --shift;
+ });
+
+ //set active selection on next element to allow "batch-deletion" by holding down DEL key
+ if (!selections.empty() && m_listBoxHistory->GetCount() > 0)
{
- //delete currently selected config history items
- wxArrayInt tmp;
- m_listBoxHistory->GetSelections(tmp);
+ int newSelection = *selections.begin();
+ if (newSelection >= static_cast<int>(m_listBoxHistory->GetCount()))
+ newSelection = m_listBoxHistory->GetCount() - 1;
+ m_listBoxHistory->SetSelection(newSelection);
+ }
+}
- std::set<int> selections(tmp.begin(), tmp.end()); //sort ascending!
- int shift = 0;
- std::for_each(selections.begin(), selections.end(),
- [&](int pos)
- {
- m_listBoxHistory->Delete(pos + shift);
- --shift;
- });
+void MainDialog::OnCfgHistoryRightClick(wxMouseEvent& event)
+{
+ ContextMenu menu;
+ menu.addItem(_("Delete"), [this] { deleteSelectedCfgHistoryItems(); });
+ menu.popup(*this);
+}
- //set active selection on next element to allow "batch-deletion" by holding down DEL key
- if (!selections.empty() && m_listBoxHistory->GetCount() > 0)
- {
- int newSelection = *selections.begin();
- if (newSelection >= static_cast<int>(m_listBoxHistory->GetCount()))
- newSelection = m_listBoxHistory->GetCount() - 1;
- m_listBoxHistory->SetSelection(newSelection);
- }
+void MainDialog::OnCfgHistoryKeyEvent(wxKeyEvent& event)
+{
+ const int keyCode = event.GetKeyCode();
+ if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE)
+ {
+ deleteSelectedCfgHistoryItems();
return; //"swallow" event
}
-
event.Skip();
}
@@ -2840,7 +2879,7 @@ void MainDialog::setConfig(const xmlAccess::XmlGuiConfig& newGuiCfg, const std::
//evaluate new settings...
//(re-)set view filter buttons
- initViewFilterButtons(newGuiCfg.mainCfg);
+ setViewFilterDefault();
updateFilterButtons();
@@ -2966,7 +3005,7 @@ void MainDialog::OnConfigureFilter(wxCommandEvent& event)
}
-void MainDialog::OnGlobalFilterContext(wxCommandEvent& event)
+void MainDialog::OnGlobalFilterContext(wxMouseEvent& event)
{
ContextMenu menu;
@@ -2983,101 +3022,15 @@ void MainDialog::OnGlobalFilterContext(wxCommandEvent& event)
}
-void MainDialog::OnLeftOnlyFiles(wxCommandEvent& event)
-{
- m_bpButtonLeftOnly->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnLeftNewerFiles(wxCommandEvent& event)
-{
- m_bpButtonLeftNewer->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnDifferentFiles(wxCommandEvent& event)
-{
- m_bpButtonDifferent->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnRightNewerFiles(wxCommandEvent& event)
-{
- m_bpButtonRightNewer->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnRightOnlyFiles(wxCommandEvent& event)
-{
- m_bpButtonRightOnly->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnEqualFiles(wxCommandEvent& event)
-{
- m_bpButtonEqual->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnConflictFiles(wxCommandEvent& event)
+void MainDialog::OnToggleViewButton(wxCommandEvent& event)
{
- m_bpButtonConflict->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncCreateLeft(wxCommandEvent& event)
-{
- m_bpButtonSyncCreateLeft->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncCreateRight(wxCommandEvent& event)
-{
- m_bpButtonSyncCreateRight->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncDeleteLeft(wxCommandEvent& event)
-{
- m_bpButtonSyncDeleteLeft->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncDeleteRight(wxCommandEvent& event)
-{
- m_bpButtonSyncDeleteRight->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncDirLeft(wxCommandEvent& event)
-{
- m_bpButtonSyncDirOverwLeft->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncDirRight(wxCommandEvent& event)
-{
- m_bpButtonSyncDirOverwRight->toggle();
- updateGui();
-}
-
-
-void MainDialog::OnSyncDirNone(wxCommandEvent& event)
-{
- m_bpButtonSyncDirNone->toggle();
- updateGui();
+ if (auto button = dynamic_cast<ToggleButton*>(event.GetEventObject()))
+ {
+ button->toggle();
+ updateGui();
+ }
+ else
+ assert(false);
}
@@ -3102,135 +3055,136 @@ wxBitmap buttonReleased(const std::string& name)
}
-void MainDialog::initViewFilterButtons(const MainConfiguration& mainCfg)
+void MainDialog::initViewFilterButtons()
{
//compare result buttons
- m_bpButtonLeftOnly->init(buttonPressed("leftOnly"),
- buttonReleased("leftOnly"),
- _("Hide files that exist on left side only"),
- _("Show files that exist on left side only"));
-
- m_bpButtonRightOnly->init(buttonPressed("rightOnly"),
- buttonReleased("rightOnly"),
- _("Hide files that exist on right side only"),
- _("Show files that exist on right side only"));
-
- m_bpButtonLeftNewer->init(buttonPressed("leftNewer"),
- buttonReleased("leftNewer"),
- _("Hide files that are newer on left"),
- _("Show files that are newer on left"));
-
- m_bpButtonRightNewer->init(buttonPressed("rightNewer"),
- buttonReleased("rightNewer"),
- _("Hide files that are newer on right"),
- _("Show files that are newer on right"));
-
- m_bpButtonEqual->init(buttonPressed("equal"),
- buttonReleased("equal"),
- _("Hide files that are equal"),
- _("Show files that are equal"));
-
- m_bpButtonDifferent->init(buttonPressed("different"),
- buttonReleased("different"),
- _("Hide files that are different"),
- _("Show files that are different"));
-
- m_bpButtonConflict->init(buttonPressed("conflict"),
- buttonReleased("conflict"),
- _("Hide conflicts"),
- _("Show conflicts"));
+ m_bpButtonShowLeftOnly->init(buttonPressed("leftOnly"),
+ buttonReleased("leftOnly"),
+ _("Hide files that exist on left side only"),
+ _("Show files that exist on left side only"));
+
+ m_bpButtonShowRightOnly->init(buttonPressed("rightOnly"),
+ buttonReleased("rightOnly"),
+ _("Hide files that exist on right side only"),
+ _("Show files that exist on right side only"));
+
+ m_bpButtonShowLeftNewer->init(buttonPressed("leftNewer"),
+ buttonReleased("leftNewer"),
+ _("Hide files that are newer on left"),
+ _("Show files that are newer on left"));
+
+ m_bpButtonShowRightNewer->init(buttonPressed("rightNewer"),
+ buttonReleased("rightNewer"),
+ _("Hide files that are newer on right"),
+ _("Show files that are newer on right"));
+
+ m_bpButtonShowEqual->init(buttonPressed("equal"),
+ buttonReleased("equal"),
+ _("Hide files that are equal"),
+ _("Show files that are equal"));
+
+ m_bpButtonShowDifferent->init(buttonPressed("different"),
+ buttonReleased("different"),
+ _("Hide files that are different"),
+ _("Show files that are different"));
+
+ m_bpButtonShowConflict->init(buttonPressed("conflict"),
+ buttonReleased("conflict"),
+ _("Hide conflicts"),
+ _("Show conflicts"));
//sync preview buttons
- m_bpButtonSyncCreateLeft->init(buttonPressed("createLeft"),
+ m_bpButtonShowCreateLeft->init(buttonPressed("createLeft"),
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"),
+ m_bpButtonShowCreateRight->init(buttonPressed("createRight"),
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"),
+ m_bpButtonShowDeleteLeft->init(buttonPressed("deleteLeft"),
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"),
+ m_bpButtonShowDeleteRight->init(buttonPressed("deleteRight"),
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"),
- buttonReleased("updateLeft"),
- _("Hide files that will be overwritten on left side"),
- _("Show files that will be overwritten on left side"));
+ m_bpButtonShowUpdateLeft->init(buttonPressed("updateLeft"),
+ 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"),
- buttonReleased("updateRight"),
- _("Hide files that will be overwritten on right side"),
- _("Show files that will be overwritten on right side"));
+ m_bpButtonShowUpdateRight->init(buttonPressed("updateRight"),
+ 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"),
- buttonReleased("none"),
- _("Hide files that won't be copied"),
- _("Show files that won't be copied"));
+ m_bpButtonShowDoNothing->init(buttonPressed("none"),
+ buttonReleased("none"),
+ _("Hide files that won't be copied"),
+ _("Show files that won't be copied"));
+}
- //compare result buttons
- m_bpButtonLeftOnly-> setActive(true);
- m_bpButtonRightOnly-> setActive(true);
- m_bpButtonLeftNewer-> setActive(true);
- m_bpButtonRightNewer->setActive(true);
- m_bpButtonDifferent-> setActive(true);
- m_bpButtonConflict-> setActive(true);
- //sync preview buttons
- m_bpButtonSyncCreateLeft-> setActive(true);
- m_bpButtonSyncCreateRight-> setActive(true);
- m_bpButtonSyncDeleteLeft-> setActive(true);
- m_bpButtonSyncDeleteRight-> setActive(true);
- m_bpButtonSyncDirOverwLeft-> setActive(true);
- m_bpButtonSyncDirOverwRight->setActive(true);
+void MainDialog::setViewFilterDefault()
+{
+ auto setButton = [](ToggleButton* tb, bool value) { tb->setActive(value); };
- m_bpButtonEqual->setActive(false);
+ const auto& def = globalCfg.gui.viewFilterDefault;
+ setButton(m_bpButtonShowLeftOnly, def.leftOnly);
+ setButton(m_bpButtonShowRightOnly, def.rightOnly);
+ setButton(m_bpButtonShowLeftNewer, def.leftNewer);
+ setButton(m_bpButtonShowRightNewer, def.rightNewer);
+ setButton(m_bpButtonShowEqual, def.equal);
+ setButton(m_bpButtonShowDifferent, def.different);
+ setButton(m_bpButtonShowConflict, def.conflict);
- //special case "m_bpButtonSyncDirNone": set always active, unless sync direction "none" is part of the rule set:
- //e.g. for a "custom" config or "update" variant. Otherwise rows with sync direction "none" can only occur on grid if the user manually
- //sets them, in which case these rows should not be hidden immediately, so m_bpButtonSyncDirNone must be active
- const std::vector<FolderPairCfg>& cmpCfg = extractCompareCfg(mainCfg);
- const bool syncDirNonePartOfConfig = std::any_of(cmpCfg.begin(), cmpCfg.end(),
- [&](const FolderPairCfg& fpCfg) -> bool
- {
- //attention: following is quite an amount of implicit/redundant knowledge here... let's hope our model is fundamental enough to not change any time soon!
-
- if (fpCfg.directionCfg.var == DirectionConfig::AUTOMATIC)
- return false;
+ setButton(m_bpButtonShowCreateLeft, def.createLeft);
+ setButton(m_bpButtonShowCreateRight,def.createRight);
+ setButton(m_bpButtonShowUpdateLeft, def.updateLeft);
+ setButton(m_bpButtonShowUpdateRight,def.updateRight);
+ setButton(m_bpButtonShowDeleteLeft, def.deleteLeft);
+ setButton(m_bpButtonShowDeleteRight,def.deleteRight);
+ setButton(m_bpButtonShowDoNothing, def.doNothing);
+}
- const DirectionSet dirSet = extractDirections(fpCfg.directionCfg);
- switch (fpCfg.compareVar)
- {
- case CMP_BY_TIME_SIZE:
- return dirSet.exLeftSideOnly == SYNC_DIR_NONE ||
- dirSet.exRightSideOnly == SYNC_DIR_NONE ||
- dirSet.leftNewer == SYNC_DIR_NONE ||
- dirSet.rightNewer == SYNC_DIR_NONE;
- //dirSet.different == SYNC_DIR_NONE ||
- //dirSet.conflict == SYNC_DIR_NONE;
+void MainDialog::OnViewButtonRightClick(wxMouseEvent& event)
+{
+ auto setButtonDefault = [](const ToggleButton* tb, bool& defaultValue)
+ {
+ if (tb->IsShown())
+ defaultValue = tb->isActive();
+ };
- case CMP_BY_CONTENT:
- return dirSet.exLeftSideOnly == SYNC_DIR_NONE ||
- dirSet.exRightSideOnly == SYNC_DIR_NONE ||
- //dirSet.leftNewer == SYNC_DIR_NONE ||
- //dirSet.rightNewer == SYNC_DIR_NONE ||
- dirSet.different == SYNC_DIR_NONE;
- //dirSet.conflict == SYNC_DIR_NONE;
- }
- assert(false);
- return false;
- });
+ auto setDefault = [&]
+ {
+ auto& def = globalCfg.gui.viewFilterDefault;
+ setButtonDefault(m_bpButtonShowLeftOnly, def.leftOnly);
+ setButtonDefault(m_bpButtonShowRightOnly, def.rightOnly);
+ setButtonDefault(m_bpButtonShowLeftNewer, def.leftNewer);
+ setButtonDefault(m_bpButtonShowRightNewer, def.rightNewer);
+ setButtonDefault(m_bpButtonShowEqual, def.equal);
+ setButtonDefault(m_bpButtonShowDifferent, def.different);
+ setButtonDefault(m_bpButtonShowConflict, def.conflict);
+
+ setButtonDefault(m_bpButtonShowCreateLeft, def.createLeft);
+ setButtonDefault(m_bpButtonShowCreateRight, def.createRight);
+ setButtonDefault(m_bpButtonShowUpdateLeft, def.updateLeft);
+ setButtonDefault(m_bpButtonShowUpdateRight, def.updateRight);
+ setButtonDefault(m_bpButtonShowDeleteLeft, def.deleteLeft);
+ setButtonDefault(m_bpButtonShowDeleteRight, def.deleteRight);
+ setButtonDefault(m_bpButtonShowDoNothing, def.doNothing);
+ };
- m_bpButtonSyncDirNone->setActive(!syncDirNonePartOfConfig);
+ ContextMenu menu;
+ menu.addItem( _("Set as default"), setDefault);
+ menu.popup(*this);
}
@@ -3316,7 +3270,7 @@ void MainDialog::OnCompare(wxCommandEvent& event)
treeDataView->setData(folderCmp); //
updateGui();
- // if (m_buttonStartSync->IsShownOnScreen()) m_buttonStartSync->SetFocus();
+ // if (m_buttonSync->IsShownOnScreen()) m_buttonSync->SetFocus();
gridview::clearSelection(*m_gridMainL, *m_gridMainC, *m_gridMainR);
m_gridNavi->clearSelection();
@@ -3353,13 +3307,13 @@ void MainDialog::updateGui()
//update sync button enabled/disabled status
if (!folderCmp.empty())
{
- m_buttonStartSync->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
- m_buttonStartSync->setBitmapFront(GlobalResources::getImage(L"sync"), 5);
+ m_buttonSync->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
+ m_buttonSync->setBitmapFront(GlobalResources::getImage(L"sync"), 5);
}
else
{
- m_buttonStartSync->SetForegroundColour(wxColor(128, 128, 128)); //Some colors seem to have problems with 16-bit desktop color, well this one hasn't!
- m_buttonStartSync->setBitmapFront(greyScale(GlobalResources::getImage(L"sync")), 5);
+ m_buttonSync->SetForegroundColour(wxColor(128, 128, 128)); //Some colors seem to have problems with 16-bit desktop color, well this one hasn't!
+ m_buttonSync->setBitmapFront(greyScale(GlobalResources::getImage(L"sync")), 5);
}
auiMgr.Update(); //fix small display distortion, if view filter panel is empty
@@ -3562,9 +3516,13 @@ void MainDialog::onGridDoubleClickR(GridClickEvent& event)
void MainDialog::onGridDoubleClickRim(size_t row, bool leftSide)
{
if (!globalCfg.gui.externelApplications.empty())
- openExternalApplication(globalCfg.gui.externelApplications[0].second,
- gridDataView->getObject(row), //optional
- leftSide);
+ {
+ std::vector<FileSystemObject*> selection;
+ if (FileSystemObject* fsObj = gridDataView->getObject(row)) //selection must be a list of BOUND pointers!
+ selection.push_back(fsObj);
+
+ openExternalApplication(globalCfg.gui.externelApplications[0].second, selection, leftSide);
+ }
}
@@ -3620,26 +3578,26 @@ void MainDialog::OnSwapSides(wxCommandEvent& event)
}
//swap view filter
- bool tmp = m_bpButtonLeftOnly->isActive();
- m_bpButtonLeftOnly->setActive(m_bpButtonRightOnly->isActive());
- m_bpButtonRightOnly->setActive(tmp);
+ bool tmp = m_bpButtonShowLeftOnly->isActive();
+ m_bpButtonShowLeftOnly->setActive(m_bpButtonShowRightOnly->isActive());
+ m_bpButtonShowRightOnly->setActive(tmp);
- tmp = m_bpButtonLeftNewer->isActive();
- m_bpButtonLeftNewer->setActive(m_bpButtonRightNewer->isActive());
- m_bpButtonRightNewer->setActive(tmp);
+ tmp = m_bpButtonShowLeftNewer->isActive();
+ m_bpButtonShowLeftNewer->setActive(m_bpButtonShowRightNewer->isActive());
+ m_bpButtonShowRightNewer->setActive(tmp);
/* for sync preview and "mirror" variant swapping may create strange effect:
- tmp = m_bpButtonSyncCreateLeft->isActive();
- m_bpButtonSyncCreateLeft->setActive(m_bpButtonSyncCreateRight->isActive());
- m_bpButtonSyncCreateRight->setActive(tmp);
+ tmp = m_bpButtonShowCreateLeft->isActive();
+ m_bpButtonShowCreateLeft->setActive(m_bpButtonShowCreateRight->isActive());
+ m_bpButtonShowCreateRight->setActive(tmp);
- tmp = m_bpButtonSyncDeleteLeft->isActive();
- m_bpButtonSyncDeleteLeft->setActive(m_bpButtonSyncDeleteRight->isActive());
- m_bpButtonSyncDeleteRight->setActive(tmp);
+ tmp = m_bpButtonShowDeleteLeft->isActive();
+ m_bpButtonShowDeleteLeft->setActive(m_bpButtonShowDeleteRight->isActive());
+ m_bpButtonShowDeleteRight->setActive(tmp);
- tmp = m_bpButtonSyncDirOverwLeft->isActive();
- m_bpButtonSyncDirOverwLeft->setActive(m_bpButtonSyncDirOverwRight->isActive());
- m_bpButtonSyncDirOverwRight->setActive(tmp);
+ tmp = m_bpButtonShowUpdateLeft->isActive();
+ m_bpButtonShowUpdateLeft->setActive(m_bpButtonShowUpdateRight->isActive());
+ m_bpButtonShowUpdateRight->setActive(tmp);
*/
//swap grid information
@@ -3659,34 +3617,34 @@ void MainDialog::updateGridViewData()
zen::UInt64 filesizeRightView;
//disable all buttons per default
- m_bpButtonLeftOnly-> Show(false);
- m_bpButtonRightOnly-> Show(false);
- m_bpButtonLeftNewer-> Show(false);
- m_bpButtonRightNewer->Show(false);
- m_bpButtonDifferent-> Show(false);
- m_bpButtonEqual-> Show(false);
- m_bpButtonConflict-> Show(false);
-
- m_bpButtonSyncCreateLeft-> Show(false);
- m_bpButtonSyncCreateRight-> Show(false);
- m_bpButtonSyncDeleteLeft-> Show(false);
- m_bpButtonSyncDeleteRight-> Show(false);
- m_bpButtonSyncDirOverwLeft-> Show(false);
- m_bpButtonSyncDirOverwRight->Show(false);
- m_bpButtonSyncDirNone-> Show(false);
+ m_bpButtonShowLeftOnly ->Show(false);
+ m_bpButtonShowRightOnly ->Show(false);
+ m_bpButtonShowLeftNewer ->Show(false);
+ m_bpButtonShowRightNewer->Show(false);
+ m_bpButtonShowDifferent ->Show(false);
+ m_bpButtonShowEqual ->Show(false);
+ m_bpButtonShowConflict ->Show(false);
+
+ m_bpButtonShowCreateLeft ->Show(false);
+ m_bpButtonShowCreateRight->Show(false);
+ m_bpButtonShowDeleteLeft ->Show(false);
+ m_bpButtonShowDeleteRight->Show(false);
+ m_bpButtonShowUpdateLeft ->Show(false);
+ m_bpButtonShowUpdateRight->Show(false);
+ m_bpButtonShowDoNothing ->Show(false);
if (showSyncAction_)
{
const GridView::StatusSyncPreview result = gridDataView->updateSyncPreview(currentCfg.hideExcludedItems,
- m_bpButtonSyncCreateLeft-> isActive(),
- m_bpButtonSyncCreateRight-> isActive(),
- m_bpButtonSyncDeleteLeft-> isActive(),
- m_bpButtonSyncDeleteRight-> isActive(),
- m_bpButtonSyncDirOverwLeft-> isActive(),
- m_bpButtonSyncDirOverwRight->isActive(),
- m_bpButtonSyncDirNone-> isActive(),
- m_bpButtonEqual-> isActive(),
- m_bpButtonConflict-> isActive());
+ m_bpButtonShowCreateLeft ->isActive(),
+ m_bpButtonShowCreateRight->isActive(),
+ m_bpButtonShowDeleteLeft ->isActive(),
+ m_bpButtonShowDeleteRight->isActive(),
+ m_bpButtonShowUpdateLeft ->isActive(),
+ m_bpButtonShowUpdateRight->isActive(),
+ m_bpButtonShowDoNothing ->isActive(),
+ m_bpButtonShowEqual ->isActive(),
+ m_bpButtonShowConflict ->isActive());
filesOnLeftView = result.filesOnLeftView;
foldersOnLeftView = result.foldersOnLeftView;
filesOnRightView = result.filesOnRightView;
@@ -3696,25 +3654,25 @@ void MainDialog::updateGridViewData()
//sync preview buttons
- m_bpButtonSyncCreateLeft-> Show(result.existsSyncCreateLeft);
- m_bpButtonSyncCreateRight-> Show(result.existsSyncCreateRight);
- m_bpButtonSyncDeleteLeft-> Show(result.existsSyncDeleteLeft);
- m_bpButtonSyncDeleteRight-> Show(result.existsSyncDeleteRight);
- m_bpButtonSyncDirOverwLeft-> Show(result.existsSyncDirLeft);
- m_bpButtonSyncDirOverwRight->Show(result.existsSyncDirRight);
- m_bpButtonSyncDirNone-> Show(result.existsSyncDirNone);
- m_bpButtonEqual-> Show(result.existsSyncEqual);
- m_bpButtonConflict-> Show(result.existsConflict);
-
- if (m_bpButtonSyncCreateLeft-> IsShown() ||
- m_bpButtonSyncCreateRight-> IsShown() ||
- m_bpButtonSyncDeleteLeft-> IsShown() ||
- m_bpButtonSyncDeleteRight-> IsShown() ||
- m_bpButtonSyncDirOverwLeft-> IsShown() ||
- m_bpButtonSyncDirOverwRight->IsShown() ||
- m_bpButtonSyncDirNone-> IsShown() ||
- m_bpButtonEqual-> IsShown() ||
- m_bpButtonConflict-> IsShown())
+ m_bpButtonShowCreateLeft ->Show(result.existsSyncCreateLeft);
+ m_bpButtonShowCreateRight ->Show(result.existsSyncCreateRight);
+ m_bpButtonShowDeleteLeft ->Show(result.existsSyncDeleteLeft);
+ m_bpButtonShowDeleteRight ->Show(result.existsSyncDeleteRight);
+ m_bpButtonShowUpdateLeft ->Show(result.existsSyncDirLeft);
+ m_bpButtonShowUpdateRight ->Show(result.existsSyncDirRight);
+ m_bpButtonShowDoNothing ->Show(result.existsSyncDirNone);
+ m_bpButtonShowEqual ->Show(result.existsSyncEqual);
+ m_bpButtonShowConflict ->Show(result.existsConflict);
+
+ if (m_bpButtonShowCreateLeft ->IsShown() ||
+ m_bpButtonShowCreateRight->IsShown() ||
+ m_bpButtonShowDeleteLeft ->IsShown() ||
+ m_bpButtonShowDeleteRight->IsShown() ||
+ m_bpButtonShowUpdateLeft ->IsShown() ||
+ m_bpButtonShowUpdateRight->IsShown() ||
+ m_bpButtonShowDoNothing ->IsShown() ||
+ m_bpButtonShowEqual ->IsShown() ||
+ m_bpButtonShowConflict ->IsShown())
{
m_panelViewFilter->Show();
m_panelViewFilter->Layout();
@@ -3726,13 +3684,13 @@ void MainDialog::updateGridViewData()
else
{
const GridView::StatusCmpResult result = gridDataView->updateCmpResult(currentCfg.hideExcludedItems,
- m_bpButtonLeftOnly-> isActive(),
- m_bpButtonRightOnly-> isActive(),
- m_bpButtonLeftNewer-> isActive(),
- m_bpButtonRightNewer->isActive(),
- m_bpButtonDifferent-> isActive(),
- m_bpButtonEqual-> isActive(),
- m_bpButtonConflict-> isActive());
+ m_bpButtonShowLeftOnly ->isActive(),
+ m_bpButtonShowRightOnly ->isActive(),
+ m_bpButtonShowLeftNewer ->isActive(),
+ m_bpButtonShowRightNewer->isActive(),
+ m_bpButtonShowDifferent ->isActive(),
+ m_bpButtonShowEqual ->isActive(),
+ m_bpButtonShowConflict ->isActive());
filesOnLeftView = result.filesOnLeftView;
foldersOnLeftView = result.foldersOnLeftView;
filesOnRightView = result.filesOnRightView;
@@ -3741,21 +3699,21 @@ void MainDialog::updateGridViewData()
filesizeRightView = result.filesizeRightView;
//comparison result view buttons
- m_bpButtonLeftOnly-> Show(result.existsLeftOnly);
- m_bpButtonRightOnly-> Show(result.existsRightOnly);
- m_bpButtonLeftNewer-> Show(result.existsLeftNewer);
- m_bpButtonRightNewer->Show(result.existsRightNewer);
- m_bpButtonDifferent-> Show(result.existsDifferent);
- m_bpButtonEqual-> Show(result.existsEqual);
- m_bpButtonConflict-> Show(result.existsConflict);
-
- if (m_bpButtonLeftOnly-> IsShown() ||
- m_bpButtonRightOnly-> IsShown() ||
- m_bpButtonLeftNewer-> IsShown() ||
- m_bpButtonRightNewer->IsShown() ||
- m_bpButtonDifferent-> IsShown() ||
- m_bpButtonEqual-> IsShown() ||
- m_bpButtonConflict-> IsShown())
+ m_bpButtonShowLeftOnly ->Show(result.existsLeftOnly);
+ m_bpButtonShowRightOnly ->Show(result.existsRightOnly);
+ m_bpButtonShowLeftNewer ->Show(result.existsLeftNewer);
+ m_bpButtonShowRightNewer->Show(result.existsRightNewer);
+ m_bpButtonShowDifferent ->Show(result.existsDifferent);
+ m_bpButtonShowEqual ->Show(result.existsEqual);
+ m_bpButtonShowConflict ->Show(result.existsConflict);
+
+ if (m_bpButtonShowLeftOnly ->IsShown() ||
+ m_bpButtonShowRightOnly ->IsShown() ||
+ m_bpButtonShowLeftNewer ->IsShown() ||
+ m_bpButtonShowRightNewer->IsShown() ||
+ m_bpButtonShowDifferent ->IsShown() ||
+ m_bpButtonShowEqual ->IsShown() ||
+ m_bpButtonShowConflict ->IsShown())
{
m_panelViewFilter->Show();
m_panelViewFilter->Layout();
@@ -3769,58 +3727,33 @@ void MainDialog::updateGridViewData()
//navigation tree
if (showSyncAction_)
treeDataView->updateSyncPreview(currentCfg.hideExcludedItems,
- m_bpButtonSyncCreateLeft-> isActive(),
- m_bpButtonSyncCreateRight-> isActive(),
- m_bpButtonSyncDeleteLeft-> isActive(),
- m_bpButtonSyncDeleteRight-> isActive(),
- m_bpButtonSyncDirOverwLeft-> isActive(),
- m_bpButtonSyncDirOverwRight->isActive(),
- m_bpButtonSyncDirNone-> isActive(),
- m_bpButtonEqual-> isActive(),
- m_bpButtonConflict-> isActive());
+ m_bpButtonShowCreateLeft ->isActive(),
+ m_bpButtonShowCreateRight->isActive(),
+ m_bpButtonShowDeleteLeft ->isActive(),
+ m_bpButtonShowDeleteRight->isActive(),
+ m_bpButtonShowUpdateLeft ->isActive(),
+ m_bpButtonShowUpdateRight->isActive(),
+ m_bpButtonShowDoNothing ->isActive(),
+ m_bpButtonShowEqual ->isActive(),
+ m_bpButtonShowConflict ->isActive());
else
treeDataView->updateCmpResult(currentCfg.hideExcludedItems,
- m_bpButtonLeftOnly-> isActive(),
- m_bpButtonRightOnly-> isActive(),
- m_bpButtonLeftNewer-> isActive(),
- m_bpButtonRightNewer->isActive(),
- m_bpButtonDifferent-> isActive(),
- m_bpButtonEqual-> isActive(),
- m_bpButtonConflict-> isActive());
+ m_bpButtonShowLeftOnly ->isActive(),
+ m_bpButtonShowRightOnly ->isActive(),
+ m_bpButtonShowLeftNewer ->isActive(),
+ m_bpButtonShowRightNewer->isActive(),
+ m_bpButtonShowDifferent ->isActive(),
+ m_bpButtonShowEqual ->isActive(),
+ m_bpButtonShowConflict ->isActive());
m_gridNavi->Refresh();
-
- //status bar
- wxWindowUpdateLocker dummy(m_panelStatusBar); //avoid display distortion
-
- //#################################################
- //update status information
- bSizerStatusLeftDirectories->Show(foldersOnLeftView > 0);
- bSizerStatusLeftFiles ->Show(filesOnLeftView > 0);
-
- setText(*m_staticTextStatusLeftDirs, replaceCpy(_P("1 directory", "%x directories", foldersOnLeftView), L"%x", toGuiString(foldersOnLeftView), false));
- setText(*m_staticTextStatusLeftFiles, replaceCpy(_P("1 file", "%x files", filesOnLeftView), L"%x", toGuiString(filesOnLeftView), false));
- setText(*m_staticTextStatusLeftBytes, filesizeToShortString(to<Int64>(filesizeLeftView)));
-
- {
- wxString statusMiddleNew;
- if (gridDataView->rowsTotal() > 0)
- {
- statusMiddleNew = _P("%x of 1 row in view", "%x of %y rows in view", gridDataView->rowsTotal());
- replace(statusMiddleNew, L"%x", toGuiString(gridDataView->rowsOnView()), false);
- replace(statusMiddleNew, L"%y", toGuiString(gridDataView->rowsTotal ()), false);
- }
- setStatusInformation(statusMiddleNew);
- }
-
- bSizerStatusRightDirectories->Show(foldersOnRightView > 0);
- bSizerStatusRightFiles ->Show(filesOnRightView > 0);
-
- setText(*m_staticTextStatusRightDirs, replaceCpy(_P("1 directory", "%x directories", foldersOnRightView), L"%x", toGuiString(foldersOnRightView), false));
- setText(*m_staticTextStatusRightFiles, replaceCpy(_P("1 file", "%x files", filesOnRightView), L"%x", toGuiString(filesOnRightView), false));
- setText(*m_staticTextStatusRightBytes, filesizeToShortString(to<Int64>(filesizeRightView)));
-
- m_panelStatusBar->Layout();
+ //update status bar information
+ setStatusBarFileStatistics(filesOnLeftView,
+ foldersOnLeftView,
+ filesOnRightView,
+ foldersOnRightView,
+ filesizeLeftView,
+ filesizeRightView);
}
@@ -3898,10 +3831,10 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event)
wxWindowUpdateLocker dummy(this); //avoid display distortion
const wxObject* const eventObj = event.GetEventObject(); //find folder pair originating the event
- for (std::vector<DirectoryPair*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i)
- if (eventObj == (*i)->m_bpButtonRemovePair)
+ for (std::vector<DirectoryPair*>::const_iterator it = additionalFolderPairs.begin(); it != additionalFolderPairs.end(); ++it)
+ if (eventObj == (*it)->m_bpButtonRemovePair)
{
- removeAddFolderPair(i - additionalFolderPairs.begin());
+ removeAddFolderPair(it - additionalFolderPairs.begin());
return;
}
}
@@ -4007,10 +3940,10 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool
for (auto it = newPairs.begin(); it != newPairs.end(); ++it)//set alternate configuration
newEntries[it - newPairs.begin()]->setValues(toWx(it->leftDirectory),
- toWx(it->rightDirectory),
- it->altCmpConfig,
- it->altSyncConfig,
- it->localFilter);
+ toWx(it->rightDirectory),
+ it->altCmpConfig,
+ it->altSyncConfig,
+ it->localFilter);
clearGrid(); //+ GUI update
}
@@ -4302,7 +4235,6 @@ void MainDialog::switchProgramLanguage(int langID)
void MainDialog::OnMenuLanguageSwitch(wxCommandEvent& event)
{
std::map<MenuItemID, LanguageID>::const_iterator it = languageMenuItemMap.find(event.GetId());
-
if (it != languageMenuItemMap.end())
switchProgramLanguage(it->second);
}
diff --git a/ui/main_dlg.h b/ui/main_dlg.h
index 4f7a6bbd..b5492101 100644
--- a/ui/main_dlg.h
+++ b/ui/main_dlg.h
@@ -90,8 +90,10 @@ private:
//used when saving configuration
std::vector<wxString> activeConfigFiles; //name of currently loaded config file (may be more than 1)
- void initViewFilterButtons(const zen::MainConfiguration& mainCfg);
- void updateFilterButtons();
+ void updateFilterButtons(); //file exclusion
+
+ void initViewFilterButtons();
+ void setViewFilterDefault();
void addFileToCfgHistory(const std::vector<wxString>& filenames); //= update/insert + apply selection
@@ -119,14 +121,15 @@ private:
void deleteSelectedFiles(const std::vector<zen::FileSystemObject*>& selectionLeft,
const std::vector<zen::FileSystemObject*>& selectionRight);
- void openExternalApplication(const wxString& commandline, const zen::FileSystemObject* fsObj, bool leftSide); //fsObj may be nullptr
+ void openExternalApplication(const wxString& commandline, const std::vector<zen::FileSystemObject*>& selection, bool leftSide); //selection may be empty
//work to be done in idle time
void OnIdleEvent(wxEvent& event);
- //delayed status information restore
- void setStatusInformation(const wxString& msg); //set main status
- void flashStatusInformation(const wxString& msg); //temporarily show different status
+ //status bar supports one of the following two states at a time:
+ void setStatusBarFullText(const wxString& msg);
+ void setStatusBarFileStatistics(size_t filesOnLeftView, size_t foldersOnLeftView, size_t filesOnRightView, size_t foldersOnRightView, zen::UInt64 filesizeLeftView, zen::UInt64 filesizeRightView);
+ void flashStatusInformation(const wxString& msg); //temporarily show different status (only valid for setStatusBarFullText)
//events
void onGridButtonEventL(wxKeyEvent& event);
@@ -138,9 +141,10 @@ private:
void OnContextSetLayout(wxMouseEvent& event);
void OnGlobalKeyEvent (wxKeyEvent& event);
- void OnCompSettingsContext(wxMouseEvent& event);
- void OnSyncSettingsContext(wxMouseEvent& event);
- void OnGlobalFilterContext(wxCommandEvent& event);
+ virtual void OnCompSettingsContext(wxMouseEvent& event);
+ virtual void OnSyncSettingsContext(wxMouseEvent& event);
+ virtual void OnGlobalFilterContext(wxMouseEvent& event);
+ virtual void OnViewButtonRightClick(wxMouseEvent& event);
void applyCompareConfig(bool switchMiddleGrid = false);
@@ -176,21 +180,7 @@ private:
void onGridLabelContextR(zen::GridClickEvent& event);
void onGridLabelContext(zen::Grid& grid, zen::ColumnTypeRim type, const std::vector<zen::ColumnAttributeRim>& defaultColumnAttributes);
- void OnLeftOnlyFiles (wxCommandEvent& event);
- void OnRightOnlyFiles (wxCommandEvent& event);
- void OnLeftNewerFiles (wxCommandEvent& event);
- void OnRightNewerFiles(wxCommandEvent& event);
- void OnEqualFiles (wxCommandEvent& event);
- void OnDifferentFiles (wxCommandEvent& event);
- void OnConflictFiles (wxCommandEvent& event);
-
- void OnSyncCreateLeft (wxCommandEvent& event);
- void OnSyncCreateRight(wxCommandEvent& event);
- void OnSyncDeleteLeft (wxCommandEvent& event);
- void OnSyncDeleteRight(wxCommandEvent& event);
- void OnSyncDirLeft (wxCommandEvent& event);
- void OnSyncDirRight (wxCommandEvent& event);
- void OnSyncDirNone (wxCommandEvent& event);
+ void OnToggleViewButton(wxCommandEvent& event);
void OnConfigNew (wxCommandEvent& event);
void OnConfigSave (wxCommandEvent& event);
@@ -200,7 +190,10 @@ private:
void OnLoadFromHistory(wxCommandEvent& event);
void OnLoadFromHistoryDoubleClick(wxCommandEvent& event);
+ void deleteSelectedCfgHistoryItems();
+
void OnCfgHistoryKeyEvent(wxKeyEvent& event);
+ void OnCfgHistoryRightClick(wxMouseEvent& event);
void OnRegularUpdateCheck(wxIdleEvent& event);
void OnLayoutWindowAsync (wxIdleEvent& event);
@@ -270,7 +263,7 @@ private:
//***********************************************
//status information
wxLongLong lastStatusChange;
- std::vector<wxString> statusMsgStack;
+ std::unique_ptr<wxString> oldStatusMsg;
//compare status panel (hidden on start, shown when comparing)
std::unique_ptr<CompareStatus> compareStatus; //always bound
diff --git a/ui/progress_indicator.cpp b/ui/progress_indicator.cpp
index 7fb04f93..13751541 100644
--- a/ui/progress_indicator.cpp
+++ b/ui/progress_indicator.cpp
@@ -123,7 +123,7 @@ void CompareStatus::CompareStatusImpl::finalize()
void CompareStatus::CompareStatusImpl::switchToCompareBytewise()
{
//start to measure perf
- perf.reset(new PerfCheck(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC));
+ perf = make_unique<PerfCheck>(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC);
lastStatCallSpeed = -1000000; //some big number
lastStatCallRemTime = -1000000;
@@ -720,9 +720,9 @@ namespace
class GraphDataBytes : public GraphData
{
public:
- void addRecord(double dataCurrent, long timeMs)
+ void addRecord(double currentBytes, long timeMs)
{
- data.insert(data.end(), std::make_pair(timeMs, dataCurrent));
+ data.insert(data.end(), std::make_pair(timeMs, currentBytes));
//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
@@ -868,8 +868,8 @@ public:
~SyncStatusImpl();
void initNewPhase();
- void reportCurrentBytes(Int64 currentData);
- void updateProgress(bool allowYield = true);
+ void notifyProgressChange();
+ void updateGui(bool allowYield = true);
//call this in StatusUpdater derived class destructor at the LATEST(!) to prevent access to currentStatusUpdater
void processHasFinished(SyncResult resultId, const ErrorLog& log);
@@ -922,6 +922,8 @@ private:
std::unique_ptr<PerfCheck> perf;
long lastStatCallSpeed; //used for calculating intervals between collecting perf samples
long lastStatCallRemTime; //
+ //help calculate total speed
+ long phaseStartMs; //begin of current phase in [ms]
std::shared_ptr<GraphDataBytes> graphDataBytes;
std::shared_ptr<GraphDataConstLine> graphDataBytesTotal;
@@ -953,7 +955,8 @@ SyncStatus::SyncStatusImpl::SyncStatusImpl(AbortCallback& abortCb,
finalResult(RESULT_ABORTED), //dummy value
isZombie(false),
lastStatCallSpeed (-1000000), //some big number
- lastStatCallRemTime(-1000000)
+ lastStatCallRemTime(-1000000),
+ phaseStartMs(0)
{
#ifdef FFS_WIN
new MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
@@ -1002,13 +1005,13 @@ SyncStatus::SyncStatusImpl::SyncStatusImpl(AbortCallback& abortCb,
graphDataBytesTotal = std::make_shared<GraphDataConstLine>();
m_panelGraph->setAttributes(Graph2D::MainAttributes().
- setLabelX(Graph2D::X_LABEL_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()).
- setLabelY(Graph2D::Y_LABEL_RIGHT, 70, std::make_shared<LabelFormatterBytes>()));
+ setLabelX(Graph2D::X_LABEL_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()).
+ setLabelY(Graph2D::Y_LABEL_RIGHT, 70, std::make_shared<LabelFormatterBytes>()));
m_panelGraph->setData(graphDataBytes,
- Graph2D::CurveAttributes().setLineWidth(2)
- .setColor (wxColor( 0, 192, 0)) //medium green
- .fillCurveArea(wxColor(192, 255, 192))); //faint green
+ Graph2D::CurveAttributes().setLineWidth(2)
+ .setColor (wxColor( 0, 192, 0)) //medium green
+ .fillCurveArea(wxColor(192, 255, 192))); //faint green
m_panelGraph->addData(graphDataBytesTotal, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 64, 0))); //dark green
@@ -1066,25 +1069,44 @@ void SyncStatus::SyncStatusImpl::initNewPhase()
//reset graph (e.g. after binary comparison)
graphDataBytes->clear();
- reportCurrentBytes(0);
+ notifyProgressChange();
//start new measurement
- perf.reset(new PerfCheck(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC));
+ perf = make_unique<PerfCheck>(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC);
lastStatCallSpeed = -1000000; //some big number
lastStatCallRemTime = -1000000;
+ phaseStartMs = timeElapsed.Time();
+
//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 updateProgress() a chance to set a different value
+ //so give updateGui() a chance to set a different value
m_gauge1->SetValue(0);
- updateProgress(false);
+ updateGui(false);
}
-void SyncStatus::SyncStatusImpl::reportCurrentBytes(Int64 currentData)
+void SyncStatus::SyncStatusImpl::notifyProgressChange() //noexcept!
{
- //add sample for perf measurements + calc. of remaining time
- graphDataBytes->addRecord(to<double>(currentData), timeElapsed.Time());
+ if (syncStat_)
+ {
+ switch (syncStat_->currentPhase())
+ {
+ case ProcessCallback::PHASE_NONE:
+ assert(false);
+ case ProcessCallback::PHASE_SCANNING:
+ break;
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ {
+ const double currentData = to<double>(syncStat_->getDataCurrent(syncStat_->currentPhase()));
+
+ //add sample for perf measurements + calc. of remaining time
+ graphDataBytes->addRecord(currentData, timeElapsed.Time());
+ }
+ break;
+ }
+ }
}
@@ -1180,7 +1202,7 @@ void SyncStatus::SyncStatusImpl::setExternalStatus(const wxString& status, const
}
-void SyncStatus::SyncStatusImpl::updateProgress(bool allowYield)
+void SyncStatus::SyncStatusImpl::updateGui(bool allowYield)
{
assert(syncStat_);
if (!syncStat_) //no sync running!!
@@ -1318,7 +1340,7 @@ void SyncStatus::SyncStatusImpl::updateProgress(bool allowYield)
while (paused_)
{
wxMilliSleep(UI_UPDATE_INTERVAL);
- updateUiNow(); //receive UI message that ends pause
+ updateUiNow(); //receive UI message that end pause
}
}
/*
@@ -1454,7 +1476,7 @@ void SyncStatus::SyncStatusImpl::closeWindowDirectly() //this should really be c
//------- change class state -------
abortCb_ = nullptr; //avoid callback to (maybe) deleted parent process
- syncStat_ = nullptr; //set *after* last call to "updateProgress"
+ syncStat_ = nullptr; //set *after* last call to "updateGui"
//----------------------------------
Close();
@@ -1471,7 +1493,8 @@ void SyncStatus::SyncStatusImpl::processHasFinished(SyncResult resultId, const E
paused_ = false; //you never know?
//update numbers one last time (as if sync were still running)
- updateProgress(false);
+ notifyProgressChange(); //make one last graph entry at the *current* time
+ updateGui(false);
switch (syncStat_->currentPhase()) //no matter if paused or not
{
@@ -1491,9 +1514,15 @@ void SyncStatus::SyncStatusImpl::processHasFinished(SyncResult resultId, const E
assert(dataCurrent <= dataTotal);
//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"
+ auto getOverallBytesPerSecond = [&]() -> wxString
+ {
+ const long timeDelta = timeElapsed.Time() - phaseStartMs; //we need to consider "time within current phase" not total "timeElapsed"!
+ if (timeDelta != 0)
+ return filesizeToShortString(dataCurrent * 1000 / timeDelta) + _("/sec");
+ return L"-"; //fallback
+ };
+
+ m_staticTextSpeed->SetLabel(getOverallBytesPerSecond());
//show new element "items processed"
m_staticTextLabelItemsProc->Show(true);
@@ -1514,7 +1543,7 @@ void SyncStatus::SyncStatusImpl::processHasFinished(SyncResult resultId, const E
//------- change class state -------
abortCb_ = nullptr; //avoid callback to (maybe) deleted parent process
- syncStat_ = nullptr; //set *after* last call to "updateProgress"
+ syncStat_ = nullptr; //set *after* last call to "updateGui"
finalResult = resultId;
//----------------------------------
@@ -1665,7 +1694,7 @@ void SyncStatus::SyncStatusImpl::minimizeToTray()
}
if (syncStat_)
- updateProgress(false); //set tray tooltip + progress: e.g. no updates while paused
+ updateGui(false); //set tray tooltip + progress: e.g. no updates while paused
Hide();
if (mainDialog)
@@ -1693,7 +1722,7 @@ void SyncStatus::SyncStatusImpl::resumeFromSystray()
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)
+ updateGui(false); //restore Windows 7 task bar progress (e.g. required in pause mode)
}
@@ -1713,7 +1742,7 @@ SyncStatus::SyncStatus(AbortCallback& abortCb,
if (showProgress)
{
pimpl->Show();
- pimpl->updateProgress(false); //clear gui flicker, remove dummy texts: window must be visible to make this work!
+ pimpl->updateGui(false); //clear gui flicker, remove dummy texts: window must be visible to make this work!
}
else
pimpl->minimizeToTray();
@@ -1734,14 +1763,14 @@ void SyncStatus::initNewPhase()
pimpl->initNewPhase();
}
-void SyncStatus::reportCurrentBytes(Int64 currentData)
+void SyncStatus::notifyProgressChange()
{
- pimpl->reportCurrentBytes(currentData);
+ pimpl->notifyProgressChange();
}
-void SyncStatus::updateProgress()
+void SyncStatus::updateGui()
{
- pimpl->updateProgress();
+ pimpl->updateGui();
}
std::wstring SyncStatus::getExecWhenFinishedCommand() const
diff --git a/ui/progress_indicator.h b/ui/progress_indicator.h
index b3d7ff2f..e4995824 100644
--- a/ui/progress_indicator.h
+++ b/ui/progress_indicator.h
@@ -49,8 +49,8 @@ public:
void initNewPhase(); //call after "StatusHandler::initNewPhase"
- void reportCurrentBytes(zen::Int64 currentData); //throw (), required by graph!
- void updateProgress();
+ void notifyProgressChange(); //throw (), required by graph!
+ void updateGui();
std::wstring getExecWhenFinishedCommand() const; //final value (after possible user modification)
diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp
index dc82ffbb..3894eb24 100644
--- a/ui/sync_cfg.cpp
+++ b/ui/sync_cfg.cpp
@@ -229,8 +229,8 @@ SyncCfgDialog::SyncCfgDialog(wxWindow* parent,
m_bitmapDatabase ->SetBitmap(GlobalResources::getImage(L"database"));
enumVersioningStyle.
- add(VER_STYLE_REPLACE, _("Replace"), _("Move files and replace if existing")).
- add(VER_STYLE_ADD_TIMESTAMP, _("Versioning"), _("Append a timestamp to each file name"));
+ add(VER_STYLE_ADD_TIMESTAMP, _("Versioning"), _("Append a timestamp to each file name")).
+ add(VER_STYLE_REPLACE, _("Replace"), _("Move files and replace if existing"));
//hide controls for optional parameters
if (!handleError && !execWhenFinished) //currently either both or neither are bound!
diff --git a/ui/tree_view.cpp b/ui/tree_view.cpp
index 5a63e579..3025dbac 100644
--- a/ui/tree_view.cpp
+++ b/ui/tree_view.cpp
@@ -395,6 +395,12 @@ TreeView::NodeStatus TreeView::getStatus(size_t row) const
void TreeView::expandNode(size_t row)
{
+ if (getStatus(row) != TreeView::STATUS_REDUCED)
+ {
+ assert(false);
+ return;
+ }
+
if (row < flatTree.size())
{
std::vector<TreeLine> newLines;
@@ -1005,6 +1011,7 @@ private:
{
case WXK_LEFT:
case WXK_NUMPAD_LEFT:
+ case WXK_NUMPAD_SUBTRACT: //http://msdn.microsoft.com/en-us/library/ms971323.aspx#atg_keyboardshortcuts_windows_shortcut_keys
if (treeDataView_)
switch (treeDataView_->getStatus(row))
{
@@ -1022,6 +1029,7 @@ private:
case WXK_RIGHT:
case WXK_NUMPAD_RIGHT:
+ case WXK_NUMPAD_ADD:
if (treeDataView_)
switch (treeDataView_->getStatus(row))
{
diff --git a/ui/triple_splitter.cpp b/ui/triple_splitter.cpp
index 8132fd13..f6ef006d 100644
--- a/ui/triple_splitter.cpp
+++ b/ui/triple_splitter.cpp
@@ -198,8 +198,12 @@ void TripleSplitter::onMouseMovement(wxMouseEvent& event)
}
else
{
- //we receive those only while above the sash, not the managed windows!
- SetCursor(wxCURSOR_SIZEWE); //set window-local only!
+ //we receive those only while above the sash, not the managed windows (except when the managed windows are disabled!)
+ const int posX = event.GetPosition().x;
+ if (hitOnSashLine(posX))
+ SetCursor(wxCURSOR_SIZEWE); //set window-local only!
+ else
+ SetCursor(*wxSTANDARD_CURSOR);
}
event.Skip();
}
diff --git a/version/version.h b/version/version.h
index 12a2a584..f5718e9d 100644
--- a/version/version.h
+++ b/version/version.h
@@ -3,7 +3,7 @@
namespace zen
{
-const wchar_t currentVersion[] = L"5.11"; //internal linkage!
+const wchar_t currentVersion[] = L"5.12"; //internal linkage!
}
#endif
diff --git a/version/version.rc b/version/version.rc
index edfff0a6..c5196a6f 100644
--- a/version/version.rc
+++ b/version/version.rc
@@ -1,2 +1,2 @@
-#define FREEFILESYNC_VER 5,11,0,0
-#define FREEFILESYNC_VER_STR "5.11\0"
+#define FREEFILESYNC_VER 5,12,0,0
+#define FREEFILESYNC_VER_STR "5.12\0"
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index 30677c80..a32c8e22 100644
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -18,8 +18,6 @@ using namespace numeric;
//todo: support zoom via mouse wheel
-warn_static("reviewreviewreviewreviewreview")
-
const wxEventType zen::wxEVT_GRAPH_SELECTION = wxNewEventType();
const std::shared_ptr<LabelFormatter> Graph2D::MainAttributes::defaultFormat = std::make_shared<DecimalNumberFormatter>(); //for some buggy reason MSVC isn't able to use a temporary as a default argument
@@ -85,9 +83,9 @@ wxColor getDefaultColor(size_t pos)
return wxColor(75, 31, 111); //purple
case 9:
return wxColor(255, 149, 14); //orange
- default:
- return *wxBLACK;
}
+ assert(false);
+ return *wxBLACK;
}
@@ -107,7 +105,6 @@ public:
{
return (realPos - min_) * scaleToScr;
}
-
int realToScreenRound(double realPos) const //useful to find "proper" y-pixel positions
{
return numeric::round(realToScreen(realPos));
@@ -120,7 +117,7 @@ private:
};
-//enlarge range to a multiple of a "useful" block size
+//enlarge value range to display to a multiple of a "useful" block size
void widenRange(double& valMin, double& valMax, //in/out
int& blockCount, //out
int graphAreaSize, //in pixel
@@ -162,10 +159,10 @@ void drawXLabel(wxDC& dc, double xMin, double xMax, int blockCount, const Conver
const int x = graphArea.x + cvrtX.realToScreenRound(valX);
if (graphArea.height > 0)
- dc.DrawLine(wxPoint(x, graphArea.y), wxPoint(x, graphArea.y + graphArea.height));
+ dc.DrawLine(wxPoint(x, graphArea.y), wxPoint(x, graphArea.y + graphArea.height)); //wxDC::DrawLine() doesn't draw last pixel
//draw x axis labels
- const wxString label = labelFmt.formatText(xMin + i * valRangePerBlock, valRangePerBlock);
+ const wxString label = labelFmt.formatText(valX, valRangePerBlock);
wxSize labelExtent = dc.GetMultiLineTextExtent(label);
dc.DrawText(label, wxPoint(x - labelExtent.GetWidth() / 2, labelArea.y + (labelArea.height - labelExtent.GetHeight()) / 2)); //center
}
@@ -191,7 +188,7 @@ void drawYLabel(wxDC& dc, double yMin, double yMax, int blockCount, const Conver
const int y = graphArea.y + cvrtY.realToScreenRound(valY);
if (graphArea.width > 0)
- dc.DrawLine(wxPoint(graphArea.x, y), wxPoint(graphArea.x + graphArea.width, y));
+ dc.DrawLine(wxPoint(graphArea.x, y), wxPoint(graphArea.x + graphArea.width, y)); //wxDC::DrawLine() doesn't draw last pixel
//draw y axis labels
const wxString label = labelFmt.formatText(valY, valRangePerBlock);
@@ -206,15 +203,14 @@ void subsample(StdContainter& cont, size_t factor)
{
if (factor <= 1) return;
- auto iterOut = cont.begin();
- for (auto iterIn = cont.begin(); cont.end() - iterIn >= static_cast<ptrdiff_t>(factor); iterIn += factor) //don't even let iterator point out of range!
- *iterOut++ = std::accumulate(iterIn, iterIn + factor, 0.0) / static_cast<double>(factor);
+ auto itOut = cont.begin();
+ for (auto itIn = cont.begin(); cont.end() - itIn >= static_cast<ptrdiff_t>(factor); itIn += factor) //don't even let iterator point out of range!
+ *itOut++ = std::accumulate(itIn, itIn + factor, 0.0) / static_cast<double>(factor);
- cont.erase(iterOut, cont.end());
+ cont.erase(itOut, cont.end());
}
}
-
Graph2D::Graph2D(wxWindow* parent,
wxWindowID winid,
const wxPoint& pos,
@@ -223,12 +219,11 @@ Graph2D::Graph2D(wxWindow* parent,
const wxString& name) : wxPanel(parent, winid, pos, size, style, name)
{
Connect(wxEVT_PAINT, wxPaintEventHandler(Graph2D::onPaintEvent), nullptr, this);
- Connect(wxEVT_SIZE, wxSizeEventHandler (Graph2D::onSizeEvent ), nullptr, this);
+ Connect(wxEVT_SIZE, wxSizeEventHandler (Graph2D::onSizeEvent ), nullptr, this);
//http://wiki.wxwidgets.org/Flicker-Free_Drawing
Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(Graph2D::onEraseBackGround), nullptr, this);
//SetDoubleBuffered(true); slow as hell!
-
#if wxCHECK_VERSION(2, 9, 1)
SetBackgroundStyle(wxBG_STYLE_PAINT);
#else
@@ -256,7 +251,6 @@ void Graph2D::OnMouseLeftDown(wxMouseEvent& event)
if (!event.ControlDown())
oldSel.clear();
-
Refresh();
}
@@ -265,7 +259,7 @@ void Graph2D::OnMouseMovement(wxMouseEvent& event)
{
if (activeSel.get())
{
- activeSel->refCurrentPos() = event.GetPosition();
+ activeSel->refCurrentPos() = event.GetPosition(); //corresponding activeSel->refSelection() is updated in Graph2D::render()
Refresh();
}
}
@@ -277,12 +271,11 @@ void Graph2D::OnMouseLeftUp(wxMouseEvent& event)
{
if (activeSel->getStartPos() != activeSel->refCurrentPos()) //if it's just a single mouse click: discard selection
{
- //fire off GraphSelectEvent
- GraphSelectEvent selEvent(activeSel->refSelection());
+ GraphSelectEvent selEvent(activeSel->refSelection()); //fire off GraphSelectEvent
if (wxEvtHandler* handler = GetEventHandler())
handler->AddPendingEvent(selEvent);
- oldSel.push_back(activeSel->refSelection());
+ oldSel.push_back(activeSel->refSelection()); //commit selection
}
activeSel.reset();
@@ -298,50 +291,45 @@ void Graph2D::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
}
-void Graph2D::setData(const std::shared_ptr<GraphData>& data, const CurveAttributes& la)
+void Graph2D::setData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca)
{
curves_.clear();
- addData(data, la);
+ addData(data, ca);
}
-void Graph2D::addData(const std::shared_ptr<GraphData>& data, const CurveAttributes& la)
+void Graph2D::addData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca)
{
- CurveAttributes newAttr = la;
+ CurveAttributes newAttr = ca;
if (newAttr.autoColor)
newAttr.setColor(getDefaultColor(curves_.size()));
curves_.push_back(std::make_pair(data, newAttr));
Refresh();
}
-
-namespace
+namespace //putting this into function scope makes MSVC crash...
{
-class DcBackgroundChanger
+struct CurveSamples
{
-public:
- DcBackgroundChanger(wxDC& dc, const wxBrush& brush) : dc_(dc), old(dc.GetBackground()) { dc.SetBackground(brush); }
- ~DcBackgroundChanger() { if (old.Ok()) dc_.SetBackground(old); }
-private:
- wxDC& dc_;
- const wxBrush old;
+ CurveSamples() : offsetX(0) {}
+ std::vector<double> yValues; //actual y-values at each screen pixel position
+ int offsetX; //x-value offset in pixels
};
}
-
void Graph2D::render(wxDC& dc) const
{
+ const wxRect clientRect = GetClientRect(); //DON'T use wxDC::GetSize()! DC may be larger than visible area!
{
- //clear everything, set label background color
- // const wxColor backColor = wxPanel::GetClassDefaultAttributes().colBg != wxNullColour ?
- // wxPanel::GetClassDefaultAttributes().colBg :
- // wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
- const wxColor backColor = GetBackgroundColour(); //user-configurable!
- DcBackgroundChanger dummy(dc, backColor); //use wxDC::SetBackground instead of wxDC::SetBrush
- dc.Clear();
+ //clear complete client area; set label background color
+ const wxColor backCol = GetBackgroundColour(); //user-configurable!
+ //wxPanel::GetClassDefaultAttributes().colBg :
+ //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+ wxDCPenChanger dummy (dc, backCol);
+ wxDCBrushChanger dummy2(dc, backCol);
+ dc.DrawRectangle(clientRect);
}
- //note: DON'T use wxDC::GetSize()! DC may be larger than visible area!
/*
-----------------------
| | x-label |
@@ -349,8 +337,7 @@ void Graph2D::render(wxDC& dc) const
|y-label | graph area |
|----------------------
*/
- const wxRect clientRect = GetClientSize(); //data window only
- wxRect graphArea = clientRect; //data window only
+ wxRect graphArea = clientRect;
int xLabelPosY = clientRect.y;
int yLabelPosX = clientRect.x;
@@ -367,7 +354,6 @@ void Graph2D::render(wxDC& dc) const
case X_LABEL_NONE:
break;
}
-
switch (attr.labelposY)
{
case Y_LABEL_LEFT:
@@ -383,17 +369,16 @@ void Graph2D::render(wxDC& dc) const
}
{
- //paint actual graph background (without labels)
- DcBackgroundChanger dummy(dc, *wxWHITE); //accessibility: we have to set both back- and foreground colors or none at all!
- wxDCPenChanger dummy2(dc, wxColour(130, 135, 144)); //medium grey, the same Win7 uses for other frame borders
- //dc.DrawRectangle(static_cast<const wxRect&>(graphArea).Inflate(1, 1)); //correct wxWidgets design mistakes
+ //paint graph background (excluding label area)
+ wxDCPenChanger dummy (dc, wxColour(130, 135, 144)); //medium grey, the same Win7 uses for other frame borders
+ wxDCBrushChanger dummy2(dc, *wxWHITE); //accessibility: we have to set both back- and foreground colors or none at all!
dc.DrawRectangle(graphArea);
- graphArea.Deflate(1, 1); //do not draw on border
+ graphArea.Deflate(1, 1); //attention more wxWidgets design mistakes: behavior of wxRect::Deflate depends on object being const/non-const!!!
}
//set label areas respecting graph area border!
- wxRect xLabelArea(graphArea.x, xLabelPosY, graphArea.width, attr.xLabelHeight);
- wxRect yLabelArea(yLabelPosX, graphArea.y, attr.yLabelWidth, graphArea.height);
+ const wxRect xLabelArea(graphArea.x, xLabelPosY, graphArea.width, attr.xLabelHeight);
+ const wxRect yLabelArea(yLabelPosX, graphArea.y, attr.yLabelWidth, graphArea.height);
const wxPoint graphAreaOrigin = graphArea.GetTopLeft();
@@ -426,7 +411,7 @@ void Graph2D::render(wxDC& dc) const
*attr.labelFmtX);
//detect y value range
- std::vector<std::pair<std::vector<double>, int>> yValuesList(curves_.size());
+ std::vector<CurveSamples> yValuesList(curves_.size());
double minY = attr.minYauto ? std::numeric_limits<double>::infinity() : attr.minY; //automatic: ensure values are initialized by first curve
double maxY = attr.maxYauto ? -std::numeric_limits<double>::infinity() : attr.maxY; //
{
@@ -434,34 +419,26 @@ void Graph2D::render(wxDC& dc) const
const ConvertCoord cvrtX(minX, maxX, graphArea.width * AVG_FACTOR);
for (auto it = curves_.begin(); it != curves_.end(); ++it)
- if (it->first.get())
+ if (const GraphData* graph = it->first.get())
{
- const size_t index = it - curves_.begin();
- const GraphData& graph = *it->first;
-
- std::vector<double>& yValues = yValuesList[index].first; //actual y-values
- int& offsetX = yValuesList[index].second; //x-value offset in pixel
+ CurveSamples& samples = yValuesList[it - curves_.begin()];
{
- const double xBegin = graph.getXBegin();
- const double xEnd = graph.getXEnd();
-
- const int posFirst = std::ceil(cvrtX.realToScreen(std::max(xBegin, minX))); //apply min/max *before* calling realToScreen()!
- const int posLast = std::ceil(cvrtX.realToScreen(std::min(xEnd, maxX))); //do not step outside [xBegin, xEnd) range => 2 x ceil!
- //conversion from std::ceil double to int is loss-free for full value range of int! tested successfully on MSVC
+ const int posFirst = std::ceil(cvrtX.realToScreen(std::max(graph->getXBegin(), minX))); //do not step outside [xBegin, xEnd) range => 2 x ceil!
+ const int posLast = std::ceil(cvrtX.realToScreen(std::min(graph->getXEnd (), maxX))); //
+ //conversion from std::ceil double return valute to int is loss-free for full value range of 32-bit int! tested successfully on MSVC
for (int i = posFirst; i < posLast; ++i)
- yValues.push_back(graph.getValue(cvrtX.screenToReal(i)));
+ samples.yValues.push_back(graph->getValue(cvrtX.screenToReal(i)));
- subsample(yValues, AVG_FACTOR);
- offsetX = posFirst / AVG_FACTOR;
+ subsample(samples.yValues, AVG_FACTOR);
+ samples.offsetX = posFirst / AVG_FACTOR;
}
-
- if (!yValues.empty())
+ if (!samples.yValues.empty())
{
if (attr.minYauto)
- minY = std::min(minY, *std::min_element(yValues.begin(), yValues.end()));
+ minY = std::min(minY, *std::min_element(samples.yValues.begin(), samples.yValues.end()));
if (attr.maxYauto)
- maxY = std::max(maxY, *std::max_element(yValues.begin(), yValues.end()));
+ maxY = std::max(maxY, *std::max_element(samples.yValues.begin(), samples.yValues.end()));
}
}
}
@@ -484,25 +461,24 @@ void Graph2D::render(wxDC& dc) const
{
if (index < yValuesList.size())
{
- const std::vector<double>& yValues = yValuesList[index].first; //actual y-values
- const int offsetX = yValuesList[index].second; //x-value offset in pixel
+ CurveSamples& samples = yValuesList[index];
- for (auto i = yValues.begin(); i != yValues.end(); ++i)
- points.push_back(wxPoint(offsetX + (i - yValues.begin()),
- cvrtY.realToScreenRound(*i)) + graphAreaOrigin);
+ for (auto it = samples.yValues.begin(); it != samples.yValues.end(); ++it)
+ points.push_back(wxPoint(samples.offsetX + (it - samples.yValues.begin()),
+ cvrtY.realToScreenRound(*it)) + graphAreaOrigin);
}
};
//update active mouse selection
if (activeSel.get() &&
- graphArea.width > 0 && graphArea.height > 0)
+ graphArea.width > 0 && graphArea.height > 0)
{
- wxPoint startPos = activeSel->getStartPos() - graphAreaOrigin; //pos relative to graphArea
+ wxPoint startPos = activeSel->getStartPos() - graphAreaOrigin; //make relative to graphArea
wxPoint currentPos = activeSel->refCurrentPos() - graphAreaOrigin;
//normalize positions: a mouse selection is symmetric and *not* an half-open range!
- confine(startPos .x, 0, graphArea.width - 1);
- confine(currentPos.x, 0, graphArea.width - 1);
+ confine(startPos .x, 0, graphArea.width - 1);
+ confine(currentPos.x, 0, graphArea.width - 1);
confine(startPos .y, 0, graphArea.height - 1);
confine(currentPos.y, 0, graphArea.height - 1);
@@ -544,14 +520,14 @@ void Graph2D::render(wxDC& dc) const
wxDCBrushChanger dummy(dc, wxColor(168, 202, 236)); //light blue
wxDCPenChanger dummy2(dc, wxColor(51, 153, 255)); //dark blue
- for (auto i = allSelections.begin(); i != allSelections.end(); ++i)
+ for (auto it = allSelections.begin(); it != allSelections.end(); ++it)
{
//harmonize with active mouse selection above!
- wxPoint pixelFrom(cvrtX.realToScreenRound(i->from.x),
- cvrtY.realToScreenRound(i->from.y));
- wxPoint pixelTo(cvrtX.realToScreenRound(i->to.x),
- cvrtY.realToScreenRound(i->to.y));
- //convert half-open to inclusive ranges for use with wxDC::DrawRectangle
+ wxPoint pixelFrom(cvrtX.realToScreenRound(it->from.x),
+ cvrtY.realToScreenRound(it->from.y));
+ wxPoint pixelTo(cvrtX.realToScreenRound(it->to.x),
+ cvrtY.realToScreenRound(it->to.y));
+ //convert half-open to inclusive ranges for use with wxDC::DrawRectangle
if (pixelFrom.x != pixelTo.x) //no matter how small the selection, always draw at least one pixel!
{
pixelFrom.x -= pixelFrom.x < pixelTo.x ? 0 : 1;
@@ -562,8 +538,8 @@ void Graph2D::render(wxDC& dc) const
pixelFrom.y -= pixelFrom.y < pixelTo.y ? 0 : 1;
pixelTo .y -= pixelFrom.y < pixelTo.y ? 1 : 0;
}
- confine(pixelFrom.x, 0, graphArea.width - 1);
- confine(pixelTo .x, 0, graphArea.width - 1);
+ confine(pixelFrom.x, 0, graphArea.width - 1);
+ confine(pixelTo .x, 0, graphArea.width - 1);
confine(pixelFrom.y, 0, graphArea.height - 1);
confine(pixelTo .y, 0, graphArea.height - 1);
@@ -600,7 +576,7 @@ void Graph2D::render(wxDC& dc) const
{
wxDCPenChanger dummy(dc, wxPen(it->second.color, it->second.lineWidth));
dc.DrawLines(static_cast<int>(points.size()), &points[0]);
- dc.DrawPoint(points.back()); //last pixel omitted by DrawLines
+ dc.DrawPoint(points.back()); //wxDC::DrawLines() doesn't draw last pixel
}
}
}
diff --git a/wx+/graph.h b/wx+/graph.h
index f5e38851..8f816b08 100644
--- a/wx+/graph.h
+++ b/wx+/graph.h
@@ -39,7 +39,6 @@ struct GraphData
//reference data implementation
-
class RangeData : public GraphData
{
public:
@@ -57,7 +56,7 @@ private:
std::vector<double> data;
};
-
+/*
//reference data implementation
class VectorData : public GraphData
{
@@ -75,6 +74,7 @@ private:
std::vector<double> data;
};
+*/
//------------------------------------------------------------------------------------------------------------
struct LabelFormatter
@@ -88,7 +88,7 @@ struct LabelFormatter
virtual wxString formatText(double value, double optimalBlockSize) const = 0;
};
-double nextNiceNumber(double blockSize); //round to next number which is convenient to read, e.g. 2.13 -> 2; 2.7 -> 2.5; 7 -> 5
+double nextNiceNumber(double blockSize); //round to next number which is convenient to read, e.g. 2.13 -> 2; 2.7 -> 2.5
struct DecimalNumberFormatter : public LabelFormatter
{
@@ -97,11 +97,11 @@ struct DecimalNumberFormatter : public LabelFormatter
};
//------------------------------------------------------------------------------------------------------------
+
//emit data selection event
//Usage: wnd.Connect(wxEVT_GRAPH_SELECTION, GraphSelectEventHandler(MyDlg::OnGraphSelection), nullptr, this);
// void MyDlg::OnGraphSelection(GraphSelectEvent& event);
-
extern const wxEventType wxEVT_GRAPH_SELECTION;
struct SelectionBlock
@@ -122,7 +122,6 @@ class GraphSelectEvent : public wxCommandEvent
{
public:
GraphSelectEvent(const SelectionBlock& selBlock) : wxCommandEvent(wxEVT_GRAPH_SELECTION), selBlock_(selBlock) {}
-
virtual wxEvent* Clone() const { return new GraphSelectEvent(selBlock_); }
SelectionBlock getSelection() { return selBlock_; }
@@ -169,8 +168,8 @@ public:
int lineWidth;
};
- void setData(const std::shared_ptr<GraphData>& data, const CurveAttributes& attr = CurveAttributes());
- void addData(const std::shared_ptr<GraphData>& data, const CurveAttributes& attr = CurveAttributes());
+ void setData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca = CurveAttributes());
+ void addData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca = CurveAttributes());
enum PosLabelY
{
@@ -214,14 +213,13 @@ public:
labelFmtY(std::make_shared<DecimalNumberFormatter>()),
mouseSelMode(SELECT_RECTANGLE) {}
-
MainAttributes& setMinX(double newMinX) { minX = newMinX; minXauto = false; return *this; }
MainAttributes& setMaxX(double newMaxX) { maxX = newMaxX; maxXauto = false; return *this; }
MainAttributes& setMinY(double newMinY) { minY = newMinY; minYauto = false; return *this; }
MainAttributes& setMaxY(double newMaxY) { maxY = newMaxY; maxYauto = false; return *this; }
- MainAttributes& setAutoSize() { minXauto = true; maxXauto = true; minYauto = true; maxYauto = true; return *this; }
+ MainAttributes& setAutoSize() { minXauto = maxXauto = minYauto = maxYauto = true; return *this; }
static const std::shared_ptr<LabelFormatter> defaultFormat;
@@ -268,7 +266,6 @@ public:
void setAttributes(const MainAttributes& newAttr) { attr = newAttr; Refresh(); }
MainAttributes getAttributes() const { return attr; }
-
std::vector<SelectionBlock> getSelections() const { return oldSel; }
void setSelections(const std::vector<SelectionBlock>& sel)
{
@@ -299,7 +296,7 @@ private:
wxPoint getStartPos() const { return posDragStart_; }
wxPoint& refCurrentPos() { return posDragCurrent; }
- SelectionBlock& refSelection() { return selBlock; } //set when selection is drawn: this is fine, 'cause only what's shown should be selected!
+ SelectionBlock& refSelection() { return selBlock; } //updated in Graph2d::render(): this is fine, since only what's shown is selected!
private:
wxWindow& wnd_;
@@ -319,5 +316,4 @@ private:
};
}
-
#endif //WX_PLOT_HEADER_2344252459
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index 5c9d3dc8..f6d0e6b8 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -328,6 +328,8 @@ public:
Connect(wxEVT_CHAR, wxKeyEventHandler(SubWindow::onChar ), nullptr, this);
Connect(wxEVT_KEY_UP, wxKeyEventHandler(SubWindow::onKeyUp ), nullptr, this);
Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(SubWindow::onKeyDown), nullptr, this);
+
+ assert(GetClientAreaOrigin() == wxPoint()); //generally assumed when dealing with coordinates below
}
Grid& refParent() { return parent_; }
@@ -483,6 +485,7 @@ public:
wxRect getRowLabelArea(ptrdiff_t row) const
{
+ assert(GetClientAreaOrigin() == wxPoint());
return wxRect(wxPoint(0, rowHeight * row),
wxSize(GetClientSize().GetWidth(), rowHeight));
}
@@ -1304,9 +1307,9 @@ private:
}
~MouseSelection() { if (wnd_.HasCapture()) wnd_.ReleaseMouse(); }
- size_t getStartRow () const { return rowStart_; }
- size_t getComponentPos () const { return compPos_; }
- size_t getCurrentRow () const { return rowCurrent_; }
+ size_t getStartRow () const { return rowStart_; }
+ size_t getComponentPos () const { return compPos_; }
+ size_t getCurrentRow () const { return rowCurrent_; }
bool isPositiveSelect() const { return positiveSelect_; } //are we selecting or unselecting?
void evalMousePos()
@@ -1322,6 +1325,7 @@ private:
wxMouseState mouseState = wxGetMouseState();
const wxPoint clientPos = wnd_.ScreenToClient(wxPoint(mouseState.GetX(), mouseState.GetY()));
const wxSize clientSize = wnd_.GetClientSize();
+ assert(wnd_.GetClientAreaOrigin() == wxPoint());
//scroll while dragging mouse
const int overlapPixY = clientPos.y < 0 ? clientPos.y :
diff --git a/wx+/pch.h b/wx+/pch.h
index b27cc656..5bfdb6cb 100644
--- a/wx+/pch.h
+++ b/wx+/pch.h
@@ -13,11 +13,11 @@
#endif
//#####################################################
+
// basic wxWidgets headers
#ifndef WX_PRECOMP
#define WX_PRECOMP
#endif
-
#include <wx/wxprec.h> //includes <wx/msw/wrapwin.h>
//other wxWidgets headers
@@ -37,7 +37,8 @@
#include <wx/config.h>
#include <wx/dc.h>
#include <wx/dialog.h>
-#include <wx/dir.h>
+//#include <wx/dir.h> -> MSVC: avoid annoying IntelliSense error: wxZipStreamLink
+//#include <wx/zipstrm.h>
#include <wx/dnd.h>
#include <wx/file.h>
#include <wx/filename.h>
@@ -70,15 +71,11 @@
#include <wx/thread.h>
#include <wx/utils.h>
#include <wx/wfstream.h>
-#include <wx/zipstrm.h>
#include <wx/scrolwin.h>
#include <wx/notebook.h>
#include <wx/help.h>
#include <wx/event.h>
-//#####################################################
-// #include other rarely changing headers here
-
//STL headers
#include <string>
#include <vector>
diff --git a/wx+/shell_execute.h b/wx+/shell_execute.h
index 6a2920e9..2531c91f 100644
--- a/wx+/shell_execute.h
+++ b/wx+/shell_execute.h
@@ -35,7 +35,7 @@ enum ExecutionType
EXEC_TYPE_ASYNC
};
-void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
+void shellExecute(const Zstring& command, ExecutionType type = EXEC_TYPE_ASYNC)
{
#ifdef FFS_WIN
//parse commandline
@@ -47,8 +47,8 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
::LocalFree(tmp);
}
- wxString filename;
- wxString arguments;
+ std::wstring filename;
+ std::wstring arguments;
if (!argv.empty())
{
filename = argv[0];
@@ -86,10 +86,10 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
if (type == EXEC_TYPE_SYNC)
{
//Posix::system - execute a shell command
- int rv = ::system(utfCvrtTo<std::string>(command).c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
+ int rv = ::system(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)"
{
- wxMessageBox(_("Invalid command line:") + L"\n" + command);
+ wxMessageBox(_("Invalid command line:") + L"\n" + utfCvrtTo<wxString>(command));
return;
}
}
@@ -100,7 +100,7 @@ void shellExecute(const wxString& command, ExecutionType type = EXEC_TYPE_ASYNC)
//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())
wxWindowDisabler dummy; //disables all top level windows
- wxExecute(command, wxEXEC_ASYNC | wxEXEC_NODISABLE);
+ wxExecute(utfCvrtTo<wxString>(command), wxEXEC_ASYNC | wxEXEC_NODISABLE);
wxLog::FlushActive(); //show wxWidgets error messages (if any)
}
#endif
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
index 5d4cfdc9..0691ac5b 100644
--- a/zen/IFileOperation/file_op.cpp
+++ b/zen/IFileOperation/file_op.cpp
@@ -84,14 +84,14 @@ public:
//IFileOperationProgressSink
virtual HRESULT STDMETHODCALLTYPE StartOperations() { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT hrResult) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostRenameItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_string LPCWSTR pszNewName, HRESULT hrRename, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreMoveItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostMoveItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrMove, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreCopyItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostCopyItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrCopy, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreNewItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostNewItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, __RPC__in_opt_string LPCWSTR pszTemplateName, DWORD dwFileAttributes, HRESULT hrNew, __RPC__in_opt IShellItem* psiNewItem) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_string LPCWSTR pszNewName, HRESULT hrRename, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrMove, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrCopy, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, __RPC__in_opt_string LPCWSTR pszTemplateName, DWORD dwFileAttributes, HRESULT hrNew, __RPC__in_opt IShellItem* psiNewItem) { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem)
{
@@ -138,8 +138,8 @@ public:
//=> defer cancellation to PreDeleteItem()/PostDeleteItem()
return S_OK;
}
- virtual HRESULT STDMETHODCALLTYPE ResetTimer() { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PauseTimer() { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE ResetTimer () { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PauseTimer () { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE ResumeTimer() { return S_OK; }
//call after IFileOperation::PerformOperations()
diff --git a/zen/basic_math.h b/zen/basic_math.h
index f8a7affd..d83a7f77 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -146,7 +146,7 @@ T confineCpy(const T& val, const T& minVal, const T& maxVal)
}
template <class T> inline
-void confine(T& val, const T& minVal, const T& maxVal) //name trim?
+void confine(T& val, const T& minVal, const T& maxVal) //name trim, clamp?
{
assert(minVal <= maxVal);
if (val < minVal)
diff --git a/zen/debug_memory_leaks.cpp b/zen/debug_memory_leaks.cpp
index 990f2ec7..2359b6ef 100644
--- a/zen/debug_memory_leaks.cpp
+++ b/zen/debug_memory_leaks.cpp
@@ -8,7 +8,7 @@
//Usage: just include this file into a Visual Studio project
-#ifndef NDEBUG
+#ifdef _DEBUG //When _DEBUG is not defined, calls to _CrtSetDbgFlag are removed during preprocessing.
#define _CRTDBG_MAP_ALLOC //
#include <stdlib.h> //keep this order: "The #include statements must be in the order shown here. If you change the order, the functions you use may not work properly."
#include <crtdbg.h> //overwrites "operator new" ect; no need to include this in every compilation unit!
@@ -27,4 +27,4 @@ struct OnStartup
} dummy;
}
-#endif \ No newline at end of file
+#endif //_DEBUG \ No newline at end of file
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index c052435a..4f34814f 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -479,8 +479,7 @@ Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short n
if (!somethingExists(output)) //ensure uniqueness
return output;
}
-
- throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...\n") + utfCvrtTo<std::string>(pathPrefix));
+ throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...") + utfCvrtTo<std::string>(pathPrefix));
}
@@ -566,10 +565,12 @@ void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw Fil
}
-class FilesDirsOnlyTraverser : public zen::TraverseCallback
+namespace
+{
+class CollectFilesFlat : public zen::TraverseCallback
{
public:
- FilesDirsOnlyTraverser(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
+ CollectFilesFlat(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
m_files(files),
m_dirs(dirs) {}
@@ -593,19 +594,17 @@ public:
virtual HandleError onError(const std::wstring& msg) { throw FileError(msg); }
private:
- FilesDirsOnlyTraverser(const FilesDirsOnlyTraverser&);
- FilesDirsOnlyTraverser& operator=(const FilesDirsOnlyTraverser&);
+ CollectFilesFlat(const CollectFilesFlat&);
+ CollectFilesFlat& operator=(const CollectFilesFlat&);
std::vector<Zstring>& m_files;
std::vector<Zstring>& m_dirs;
};
-void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
+void removeDirectoryImpl(const Zstring& directory, CallbackRemoveDir* callback) //throw FileError
{
- //no error situation if directory is not existing! manual deletion relies on it!
- if (!somethingExists(directory))
- return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ assert(somethingExists(directory)); //[!]
#ifdef FFS_WIN
const Zstring directoryFmt = applyLongPathPrefix(directory); //support for \\?\-prefix
@@ -617,55 +616,66 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
//attention: check if directory is a symlink! Do NOT traverse into it deleting contained files!!!
if (symlinkExists(directory)) //remove symlink directly
{
+ if (callback) callback->onBeforeDirDeletion(directory); //once per symlink
#ifdef FFS_WIN
if (!::RemoveDirectory(directoryFmt.c_str()))
#elif defined FFS_LINUX
if (::unlink(directory.c_str()) != 0)
#endif
throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
-
- if (callback)
- callback->notifyDirDeletion(directory); //once per symlink
- return;
}
-
- std::vector<Zstring> fileList;
- std::vector<Zstring> dirList;
+ else
{
- //get all files and directories from current directory (WITHOUT subdirectories!)
- FilesDirsOnlyTraverser traverser(fileList, dirList);
- traverseFolder(directory, traverser); //don't follow symlinks
- }
+ std::vector<Zstring> fileList;
+ std::vector<Zstring> dirList;
+ {
+ //get all files and directories from current directory (WITHOUT subdirectories!)
+ CollectFilesFlat cff(fileList, dirList);
+ traverseFolder(directory, cff); //don't follow symlinks
+ }
- //delete directories recursively
- for (auto it = dirList.begin(); it != dirList.end(); ++it)
- removeDirectory(*it, callback); //call recursively to correctly handle symbolic links
+ //delete directories recursively
+ std::for_each(dirList.begin(), dirList.end(),
+ [&](const Zstring& dirname)
+ {
+ removeDirectoryImpl(dirname, callback); //throw FileError; call recursively to correctly handle symbolic links
+ });
- //delete files
- for (auto it = fileList.begin(); it != fileList.end(); ++it)
- {
- const bool workDone = removeFile(*it);
- if (callback && workDone)
- callback->notifyFileDeletion(*it); //call once per file
- }
+ //delete files
+ std::for_each(fileList.begin(), fileList.end(),
+ [&](const Zstring& filename)
+ {
+ if (callback) callback->onBeforeFileDeletion(filename); //call once per file
+ removeFile(filename); //throw FileError
+ });
- //parent directory is deleted last
+ //parent directory is deleted last
+ if (callback) callback->onBeforeDirDeletion(directory); //and once per folder
#ifdef FFS_WIN
- if (!::RemoveDirectory(directoryFmt.c_str()))
+ if (!::RemoveDirectory(directoryFmt.c_str()))
#else
- if (::rmdir(directory.c_str()) != 0)
+ if (::rmdir(directory.c_str()) != 0)
#endif
- throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
- //may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
- //successfully been *marked* for deletion, but some application still has a handle open!
- //e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
- //Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
-
- if (callback)
- callback->notifyDirDeletion(directory); //and once per folder
+ throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
+ //may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
+ //successfully been *marked* for deletion, but some application still has a handle open!
+ //e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
+ //Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
+ }
+}
}
+void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
+{
+ //no error situation if directory is not existing! manual deletion relies on it!
+ if (!somethingExists(directory))
+ return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ removeDirectoryImpl(directory, callback);
+}
+
+
+
void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl) //throw FileError
{
#ifdef FFS_WIN
@@ -917,11 +927,6 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
assert(::CompareFileTime(&creationTimeDbg, &creationTime) == 0);
assert(::CompareFileTime(&lastWriteTimeDbg, &lastWriteTime) == 0);
}
- //CAVEAT on FAT/FAT32: the sequence of deleting the target file and renaming "file.txt.ffs_tmp" to "file.txt" seems to
- //NOT PRESERVE the creation time of the .ffs_tmp file, but "reuses" whatever creation time the old "file.txt" had!
- //this problem is therefore NOT detected by the check above!
- //However during the next comparison the DST hack will be applied correctly.
-
#endif
#elif defined FFS_LINUX
@@ -2303,6 +2308,27 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
//perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick!
renameFile(temporary, targetFile); //throw FileError
+ /*
+ CAVEAT on FAT/FAT32: the sequence of deleting the target file and renaming "file.txt.ffs_tmp" to "file.txt" does
+ NOT PRESERVE the creation time of the .ffs_tmp file, but SILENTLY "reuses" whatever creation time the old "file.txt" had!
+ This "feature" is called "File System Tunneling":
+ http://blogs.msdn.com/b/oldnewthing/archive/2005/07/15/439261.aspx
+ http://support.microsoft.com/kb/172190/en-us
+
+ However during the next comparison the DST hack will be applied correctly since the DST-hash of the mod.time is invalid.
+
+ EXCEPTION: the hash may match!!! reproduce:
+ 1. set system time back to date within previous DST
+ 2. save some file on FAT32 usb stick and FFS-compare to make sure the DST hack is applied correctly
+ 4. pull out usb stick, put back in
+ 3. restore system time
+ 4. copy file from USB to local drive via explorer
+ =>
+ NTFS <-> FAT, file exists on both sides; mod times match, DST hack on USB stick causes 1-hour offset when comparing in FFS.
+ When syncing modification time is copied correctly, but new DST hack fails to apply and old creation time is reused (see above).
+ Unfortunately, the old DST hash matches mod time! => On next comparison FFS will *still* see both sides as different!!!!!!!!!
+ */
+
guardTempFile.dismiss();
}
else
diff --git a/zen/file_handling.h b/zen/file_handling.h
index e9e1685d..5739dc2a 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -47,7 +47,7 @@ UInt64 getFilesize(const Zstring& filename); //throw FileError
UInt64 getFreeDiskSpace(const Zstring& path); //throw FileError
//file handling
-bool removeFile(const Zstring& filename); //throw FileError; return "true" if file was actually deleted
+bool removeFile(const Zstring& filename); //throw FileError; return "false" if file is not existing
void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nullptr); //throw FileError
//rename file or directory: no copying!!!
@@ -57,7 +57,7 @@ bool supportsPermissions(const Zstring& dirname); //throw FileError, derefernces
//creates superdirectories automatically:
void makeDirectory(const Zstring& directory); //throw FileError; do nothing if directory already exists!
-void makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //FileError, ErrorTargetExisting
+void makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //throw FileError, ErrorTargetExisting
struct FileAttrib
{
@@ -85,16 +85,15 @@ void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copy
struct CallbackRemoveDir
{
virtual ~CallbackRemoveDir() {}
- virtual void notifyFileDeletion(const Zstring& filename) = 0; //one call for each (existing) object!
- virtual void notifyDirDeletion (const Zstring& dirname ) = 0; //
+ virtual void onBeforeFileDeletion(const Zstring& filename) = 0; //one call for each *existing* object!
+ virtual void onBeforeDirDeletion (const Zstring& dirname ) = 0; //
};
-
struct CallbackCopyFile
{
virtual ~CallbackCopyFile() {}
- //if target is existing user needs to implement deletion: copyFile() NEVER deletes target if already existing!
+ //if target is existing user needs to implement deletion: copyFile() NEVER overwrites target if already existing!
//if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it.
virtual void deleteTargetFile(const Zstring& targetFile) = 0; //may throw exceptions
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index d8a99a4d..c8ef6550 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -12,7 +12,6 @@
#include "int64.h"
#include "file_id_def.h"
-
//advanced file traverser returning metadata and hierarchical information on files and directories
namespace zen
@@ -25,8 +24,8 @@ struct TraverseCallback
{
UInt64 fileSize; //unit: bytes!
Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC
- FileId id; //optional: may be initial!
- //bool isFollowedSymlink;
+ FileId id; //optional: initial if not supported!
+ //std::unique_ptr<SymlinkInfo> symlinkInfo; //only filled if file is dereferenced symlink
};
struct SymlinkInfo
@@ -48,7 +47,6 @@ struct TraverseCallback
ON_ERROR_IGNORE
};
- //overwrite these virtual methods
virtual std::shared_ptr<TraverseCallback> //nullptr: ignore directory, non-nullptr: traverse into using the (new) callback
/**/ onDir (const Zchar* shortName, const Zstring& fullName) = 0;
virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) = 0;
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 8e5b04d3..6455029f 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -199,7 +199,7 @@ private:
//convert LOCALE_SGROUPING to Grouping: http://blogs.msdn.com/b/oldnewthing/archive/2006/04/18/578251.aspx
replace(grouping, L';', L"");
if (endsWith(grouping, L'0'))
- grouping.resize(grouping.size() - 1);
+ grouping.pop_back();
else
grouping += L'0';
fmt.Grouping = stringTo<UINT>(grouping);
@@ -253,7 +253,7 @@ std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
if (i <= 3)
break;
i -= 3;
- if (!isDigit(output[i - 1]))
+ if (!isDigit(output[i - 1])) //stop on +, - signs
break;
output.insert(i, thousandSep);
}
diff --git a/zen/guid.h b/zen/guid.h
index 823f4431..0c03bd9f 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()(); //generator is thread-safe like an int
+ boost::uuids::uuid nativeRep = boost::uuids::random_generator()();
+ //generator is only thread-safe like an int, so we keep it local until we need to optimize perf
//perf: generator: 0.22ms per call; retrieve GUID: 0.12s per call
return std::string(nativeRep.begin(), nativeRep.end());
}
diff --git a/zen/perf.h b/zen/perf.h
index 92350602..4a334bff 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -29,11 +29,13 @@ public:
class TimerError {};
ZEN_DEPRECATE
- PerfTimer() : ticksPerSec_(ticksPerSec()), startTime(), resultShown(false)
+ PerfTimer() : //throw TimerError
+ ticksPerSec_(ticksPerSec()), startTime(), resultShown(false)
{
//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
+ if (::SetThreadAffinityMask(::GetCurrentThread(), 1) == 0) //"should not be required unless there are bugs in BIOS or HAL" - msdn, QueryPerformanceCounter
+ throw TimerError();
#endif
startTime = getTicks();
if (ticksPerSec_ == 0 || !startTime.isValid())
diff --git a/zen/process_priority.h b/zen/process_priority.h
index 15266b28..c0bae667 100644
--- a/zen/process_priority.h
+++ b/zen/process_priority.h
@@ -12,7 +12,7 @@ namespace zen
struct PreventStandby //signal a "busy" state to the operating system
{
#ifdef FFS_WIN
- PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); }
+ PreventStandby () { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); }
~PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS); }
#endif
};
@@ -26,8 +26,8 @@ struct ScheduleForBackgroundProcessing //lower CPU and file I/O priorities
#define PROCESS_MODE_BACKGROUND_END 0x00200000 //
#endif
- ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } //this call lowers CPU priority, too!!
- ~ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); }
+ ScheduleForBackgroundProcessing () { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } //this call lowers CPU priority, too!!
+ ~ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END ); }
#elif defined FFS_LINUX
/*
diff --git a/zen/recycler.h b/zen/recycler.h
index 4d33477d..8aca0ff3 100644
--- a/zen/recycler.h
+++ b/zen/recycler.h
@@ -42,13 +42,14 @@ enum StatusRecycler
STATUS_REC_UNKNOWN
};
StatusRecycler recycleBinStatus(const Zstring& pathName); //test existence of Recycle Bin API for certain path
+//Win: blocks heavily if recycle bin is really full and drive is slow!!!
struct CallbackRecycling
{
virtual ~CallbackRecycling() {}
//may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected
- virtual void updateStatus(const Zstring& currentItem) = 0;
+ virtual void updateStatus(const Zstring& currentItem) = 0; //currentItem may be empty
};
void recycleOrDelete(const std::vector<Zstring>& filenames, //throw FileError, return "true" if file/dir was actually deleted
diff --git a/zen/string_base.h b/zen/string_base.h
index bfe573e9..e4e21716 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -15,7 +15,6 @@
//Zbase - a policy based string class optimizing performance and genericity
-
namespace zen
{
/*
@@ -59,8 +58,8 @@ template <typename Char, //Character Type
void setLength(Char* ptr, size_t newLength)
*/
-template <typename Char, //Character Type
- class AP> //Allocator Policy
+template <class Char, //Character Type
+ class AP> //Allocator Policy
class StorageDeepCopy : public AP
{
protected:
@@ -112,8 +111,8 @@ private:
};
-template <typename Char, //Character Type
- class AP> //Allocator Policy
+template <class Char, //Character Type
+ class AP> //Allocator Policy
class StorageRefCountThreadSafe : public AP
{
protected:
@@ -169,7 +168,7 @@ private:
{
Descriptor(long rc, size_t len, size_t cap) :
refCount(rc),
- length(static_cast<std::uint32_t>(len)),
+ length (static_cast<std::uint32_t>(len)),
capacity(static_cast<std::uint32_t>(cap)) {}
boost::detail::atomic_count refCount; //practically no perf loss: ~0.2%! (FFS comparison)
@@ -181,8 +180,8 @@ private:
static Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; }
static const Descriptor* descr(const Char* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; }
};
-//################################################################################################################################################################
+//################################################################################################################################################################
//perf note: interstingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison
@@ -386,7 +385,7 @@ size_t Zbase<Char, SP, AP>::find(const Zbase& str, size_t pos) const
assert(pos <= length());
const Char* thisEnd = end(); //respect embedded 0
const Char* it = std::search(begin() + pos, thisEnd,
- str.begin(), str.end());
+ str.begin(), str.end());
return it == thisEnd ? npos : it - begin();
}
@@ -397,7 +396,7 @@ size_t Zbase<Char, SP, AP>::find(const Char* str, size_t pos) const
assert(pos <= length());
const Char* thisEnd = end(); //respect embedded 0
const Char* it = std::search(begin() + pos, thisEnd,
- str, str + strLength(str));
+ str, str + strLength(str));
return it == thisEnd ? npos : it - begin();
}
@@ -433,7 +432,7 @@ size_t Zbase<Char, SP, AP>::rfind(const Char* str, size_t pos) const
const Char* currEnd = pos == npos ? end() : begin() + std::min(pos + strLen, length());
const Char* it = search_last(begin(), currEnd,
- str, str + strLen);
+ str, str + strLen);
return it == currEnd ? npos : it - begin();
}
diff --git a/zen/thread.h b/zen/thread.h
index 31d762c7..43917d13 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -33,8 +33,11 @@
namespace zen
{
-//until std::async is available:
/*
+std::async replacement without crappy semantics:
+ 1. guaranteed to run asynchronous
+ 2. does not follow C++11 [futures.async], Paragraph 5, where std::future waits for thread in destructor
+
Example:
Zstring dirname = ...
auto ft = zen::async([=](){ return zen::dirExists(dirname); });
@@ -93,10 +96,13 @@ private:
template <class T, class Function> inline
auto async2(Function fun) -> boost::unique_future<T> //support for workaround of VS2010 bug: bool (*fun)(); decltype(fun()) == int!
{
- boost::packaged_task<T> pt(std::move(fun)); //packaged task seems to even require r-value reference: https://sourceforge.net/p/freefilesync/bugs/234/
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK //mirror "boost/thread/future.hpp", hopefully they know what they're doing
+ boost::packaged_task<T()> pt(std::move(fun)); //packaged task seems to even require r-value reference: https://sourceforge.net/p/freefilesync/bugs/234/
+#else
+ boost::packaged_task<T> pt(std::move(fun));
+#endif
auto fut = pt.get_future();
- boost::thread t(std::move(pt));
- t.detach(); //we have to be explicit since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
+ boost::thread(std::move(pt)).detach(); //we have to explicitly detach since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
return std::move(fut); //compiler error without "move", why needed???
}
bgstack15