diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:04:59 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:04:59 +0200 |
commit | f570e2f2685aa43aa518c2f8578391c1847cddbe (patch) | |
tree | b9376b3a7e807c5e0c4cf3d5615c14034d9675d6 | |
parent | 3.2 (diff) | |
download | FreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.tar.gz FreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.tar.bz2 FreeFileSync-f570e2f2685aa43aa518c2f8578391c1847cddbe.zip |
3.3
123 files changed, 5951 insertions, 3025 deletions
diff --git a/Application.cpp b/Application.cpp index 04b687b8..6b17bc19 100644 --- a/Application.cpp +++ b/Application.cpp @@ -246,6 +246,7 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet FreeFileSync::CompareProcess comparison(batchCfg.mainCfg.hidden.traverseDirectorySymlinks, batchCfg.mainCfg.hidden.fileTimeTolerance, globSettings.ignoreOneHourDiff, + globSettings.detectRenameThreshold, globSettings.optDialogs, statusHandler.get()); diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt index efd4697e..5bc1a41b 100644 --- a/BUILD/Changelog.txt +++ b/BUILD/Changelog.txt @@ -2,6 +2,26 @@ |FreeFileSync| -------------- +Changelog v3.3 +-------------- +New installer package for portable/local/32/64-bit versions +Built-in support for very long filenames: apply \\?\-prefix automatically +New button for synchonization preview: show equal files +RealtimeSync: Respond to directory or volume arrival, e.g. USB stick insert +Start comparison automatically when double-clicking on *.ffs_gui files +Visual progress indicator for sys-tray icon +Fixed string comparison for 'ß' and 'ss' (all Windows versions) +Fixed general string comparison for Windows 2000 +Significantly faster file icon loading +Applied new IFileOperation interface for recycle bin (Windows >= Vista) +Patched <Automatic> mode to handle FAT32 2-second file time precision +Play optional sound after comparison: "Compare_Complete.wav" +Allow environment variables for logfile-directory +Enhanced conflict reporting +Added Swedish translation +Updated translation files + + Changelog v3.2 -------------- Native Windows 64-Bit version (including Volume Shadow Copy Service) diff --git a/BUILD/Compare_Complete.wav b/BUILD/Compare_Complete.wav Binary files differnew file mode 100644 index 00000000..f304e6d7 --- /dev/null +++ b/BUILD/Compare_Complete.wav diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm Binary files differindex 3cf06742..139df0e1 100644 --- a/BUILD/FreeFileSync.chm +++ b/BUILD/FreeFileSync.chm diff --git a/BUILD/Help/html/Features.html b/BUILD/Help/html/Features.html index 75aea41d..7a40fcdb 100644 --- a/BUILD/Help/html/Features.html +++ b/BUILD/Help/html/Features.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.0 (Win32)"> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.1 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091207;23033200"> + <META NAME="CHANGED" CONTENT="20100124;542600"> <STYLE TYPE="text/css"> <!-- @page { margin: 2cm } @@ -30,6 +30,9 @@ support.</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Network support.</FONT></P> + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Built-in + support for very long filenames (more than MAX_PATH = 260 + characters)</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Synchronization database for propagation of deleted files and conflict detection</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Support @@ -42,11 +45,11 @@ of data.</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Algorithms coded in C++ completely.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">All + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">All progress indicators optimized for maximum performance!</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Create + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create Batch Jobs for automated synchronization with or without GUI.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Focus + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Focus on usability:</FONT></P> <OL TYPE=a> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Only @@ -73,41 +76,39 @@ </OL> </OL> <OL START=14> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Support + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Support for filesizes larger than 4 GB.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Option + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Option to move files to Recycle Bin instead of deleting/overwriting them.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Ignore + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Ignore directories "\RECYCLER" and "\System Volume - Information" with default Filter. (Windows only)</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Localized + Information" with default filter. (Windows only)</FONT></P> + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Localized versions are available for many languages.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Delete + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Delete before copy: Avoid disc space shortages for large sync-jobs.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Filter + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Filter functionality to include/exclude files from synchronization (without requiring a re-compare!).</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Include/exclude + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Include/exclude specific files from synchronization temporarily.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Create + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create sync jobs via GUI to synchronize automatically (can be scheduled or executed via double-click).</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Handle + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Handle daylight saving time changes on FAT/FAT32 volumes correctly.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Portable + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Portable version (.zip) available.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Native + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Native 64-Bit version.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Support - for \\?\ path prefix for unrestricted path length. (Windows only)</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Check + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Check for updates from within FreeFileSync automatically.</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Copy + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Copy locked files using Windows Volume Shadow Copy Service. (Windows only)</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Create + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create regular backups with macros %time%, %date% within directory names</FONT></P> - <LI><P STYLE="margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Copy + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Copy file and folder create/access/modification times when synchronizing</FONT></P> </OL> </BODY> diff --git a/BUILD/Help/html/advanced/EnvironmentVariables.html b/BUILD/Help/html/advanced/EnvironmentVariables.html index 2d4f6069..c3e80ce7 100644 --- a/BUILD/Help/html/advanced/EnvironmentVariables.html +++ b/BUILD/Help/html/advanced/EnvironmentVariables.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;15581900"> + <META NAME="CHANGED" CONTENT="20091217;17435700"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -34,15 +34,15 @@ character. Besides special macros handling time and date (see environment variables can also be used.</FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Example:</B></FONT></P> <UL> - <P STYLE="margin-bottom: 0cm"><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> + <P><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> <UL> <LI><P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif"><FONT FACE="Courier New, monospace">C:\Backup\%USERNAME%_Config </FONT>expands to<FONT FACE="Courier New, monospace"><BR>C:\Backup\ZenJu_Config</FONT></FONT></P> <LI><P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"> - <FONT FACE="Tahoma, sans-serif"><FONT FACE="Courier New, monospace">%USERPROFILE%\Application - Data\FreeFileSync </FONT>expands to<FONT FACE="Courier New, monospace"><BR>C:\Documents - and Settings\ZenJu\Application Data\FreeFileSync</FONT></FONT></P> + <FONT FACE="Tahoma, sans-serif"><FONT FACE="Courier New, monospace">%APPDATA%\FreeFileSync </FONT>expands + to<FONT FACE="Courier New, monospace"><BR>C:\Documents and + Settings\ZenJu\Application Data\FreeFileSync</FONT></FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> @@ -63,7 +63,7 @@ batch configuration file <FONT FACE="Courier New, monospace">C:\SyncJob.ffs_batc </FONT>instead of an absolute target directory and is invoked by a *.cmd file:</FONT></P> <UL> - <P STYLE="margin-bottom: 0cm"><SPAN ID="Rahmen2" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> + <P><SPAN ID="Rahmen2" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> <UL> <P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><FONT FACE="Courier New, monospace">set MyVar=C:\Target<BR>cd "C:\Program @@ -78,7 +78,7 @@ batch configuration file <FONT FACE="Courier New, monospace">C:\SyncJob.ffs_batc <P STYLE="margin-bottom: 0cm"><BR> </P> <UL> - <P STYLE="margin-bottom: 0cm"><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: 1px solid #000080; padding: 0.05cm; background: #ccccff"> + <P><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: 1px solid #000080; padding: 0.05cm; background: #ccccff"> <P ALIGN=LEFT STYLE="margin-left: 0.79cm; margin-right: 0.98cm; margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif"><B>Note:</B><BR>Temporary environment variables created with the "<FONT FACE="Courier New, monospace">set</FONT>" diff --git a/BUILD/Help/html/advanced/RealtimeSync.html b/BUILD/Help/html/advanced/RealtimeSync.html index 7eac013c..156409ba 100644 --- a/BUILD/Help/html/advanced/RealtimeSync.html +++ b/BUILD/Help/html/advanced/RealtimeSync.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;16073500"> + <META NAME="CHANGED" CONTENT="20100125;20445600"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -21,7 +21,7 @@ --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">RealtimeSync</FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> @@ -30,41 +30,46 @@ primary function is to trigger synchronization immediately after files in a source directory have changed. However its implementation is much more flexible to cover an even broader range of use: A list of directories provided by the user is monitored for changes. -Whenever a file or a subdirectory is modified, RealtimeSync responds -by executing the user-specified commandline.</FONT></P> +Whenever a file within these directories or subdirectories is +modified OR the directory becomes available (e.g. insert of a +USB-stick), RealtimeSync responds by executing the user-specified +command line.</FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Example:</B></FONT> <FONT FACE="Tahoma, sans-serif">(Real time synchronization - in combination with FreeFileSync)</FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">First -specify all directories that shall be monitored. Instead of doing -this manually you can simply import a *.ffs_batch file via </FONT><FONT FACE="Tahoma, sans-serif"><I>Menu +start up RealtimeSync.exe located in FreeFileSync's installation +directory. Then specify all directories that shall be monitored. +Instead of doing this manually you can simply import a </FONT><FONT FACE="Courier New, monospace">*.ffs_batch</FONT> +<FONT FACE="Tahoma, sans-serif">file via </FONT><FONT FACE="Tahoma, sans-serif"><I>Menu -> File -> Load configuration</I></FONT><FONT FACE="Tahoma, sans-serif">. This not only extracts all directories relevant for synchronization -but also sets up the commandline to execute the *.ffs_batch file -every time changes are detected. Then press start to begin -monitoring.</FONT></P> +but also sets up the command-line to execute the </FONT><FONT FACE="Courier New, monospace">*.ffs_batch</FONT> +<FONT FACE="Tahoma, sans-serif">file every time changes are detected. +Now press "</FONT><FONT FACE="Tahoma, sans-serif"><I>Start</I></FONT><FONT FACE="Tahoma, sans-serif">" +to begin monitoring.</FONT></P> <UL> - <P STYLE="margin-bottom: 0cm"><IMG SRC="RealtimeSync_html_72dda21b.gif" NAME="Grafik1" ALIGN=MIDDLE WIDTH=382 HEIGHT=395 BORDER=0></P> + <P STYLE="margin-bottom: 0cm"><IMG SRC="rts23.png" NAME="Grafik3" ALIGN=MIDDLE WIDTH=503 HEIGHT=429 BORDER=0></P> </UL> <P STYLE="margin-bottom: 0cm"><BR> </P> <UL> - <P STYLE="margin-bottom: 0cm"><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: 1px solid #000080; padding: 0.05cm; background: #ccccff"> + <P><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: 1px solid #000080; padding: 0.05cm; background: #ccccff"> <UL> <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-right: 0.98cm; margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Using RealtimeSync is not - restricted to starting FreeFileSync. It can also be used for other + restricted to starting FreeFileSync. It can also be used in other scenarios, like sending an email whenever a certain directory is modified.</FONT></P> <LI><P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"> <FONT FACE="Tahoma, sans-serif">Starting the tool can be automated - by passing a RealtimeSync configuration file (*.ffs_real) OR a - FreeFileSync Batch file (*.ffs_batch) as first commandline - argument. This allows for integration with your operating system's - autostart facility:</FONT></P> + by passing a RealtimeSync configuration file (<FONT FACE="Courier New, monospace">*.ffs_real</FONT>) + OR a FreeFileSync Batch file (<FONT FACE="Courier New, monospace">*.ffs_batch</FONT>) + as first command-line argument. This allows for integration with + your operating system's autostart facility:</FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> @@ -72,13 +77,73 @@ monitoring.</FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> <UL> + <P><SPAN ID="Rahmen2" 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">"C:\Program + Files\FreeFileSync\RealtimeSync.exe" + "C:\MyConfig.ffs_real"<BR>"C:\Program + Files\FreeFileSync\RealtimeSync.exe" "C:\SyncJob.ffs_batch"</FONT></P> + </SPAN><BR CLEAR=LEFT> + </P> +</UL> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Example:</B></FONT> +<FONT FACE="Tahoma, sans-serif">(Smart synchronization when USB +sticks are inserted into your PC - in combination with FreeFileSync)</FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Assume +you have multiple(!) USB sticks that contain data you want to +automatically synchronize in two-way mode whenever you insert one of +the sticks into the PC. In order to be on the safe side, you decide +to setup FreeFileSync batch jobs (</FONT><FONT FACE="Courier New, monospace">*.ffs_batch</FONT><FONT FACE="Tahoma, sans-serif">) +using </FONT><FONT FACE="Tahoma, sans-serif"><I><Automatic></I></FONT> +<FONT FACE="Tahoma, sans-serif">mode so that conflicts, for example +files modified on both sides, are detected avoiding data loss. Save +the relevant configuration on each USB stick's root directory to have +it called when the stick is mounted. Then configure RealtimeSync +analog to the following:</FONT></P> +<UL> + <P><IMG SRC="rts.png" NAME="Grafik2" ALIGN=BOTTOM WIDTH=462 HEIGHT=411 BORDER=0></P> +</UL> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Whenever +directory "</FONT><FONT FACE="Courier New, monospace">H:\Data</FONT><FONT FACE="Tahoma, sans-serif">" +becomes available, the command-line executes and starts the batchjob +whose configuration is located on the stick. Furthermore it also +starts the batch job each time files are modified within "</FONT><FONT FACE="Courier New, monospace">H:\Data</FONT><FONT FACE="Tahoma, sans-serif">". +</FONT> +</P> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">For +additional convenience it might be nice if the batch job remains +silent if synchronization completes successfully, otherwise shows +FreeFileSync's GUI dialog when errors occurred. Therefore create two +configurations, one silent-mode batch to be called by default and one +<FONT FACE="Courier New, monospace">*.ffs_gui</FONT> to be called +when former fails. Then replace the command-line to simply execute a +batch file similar to this one:</FONT></P> +<UL> <P><SPAN ID="Rahmen1" 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">C:\Program - Files\FreeFileSync\RealtimeSync.exe C:\MyConfig.ffs_real<BR>C:\Program - Files\FreeFileSync\RealtimeSync.exe C:\SyncJob.ffs_batch</FONT></P> + <FONT COLOR="#808080"><FONT FACE="Courier New, monospace"><I><B>::first + check whether USB-stick contains a sync-configuration at all</B></I></FONT></FONT><FONT FACE="Courier New, monospace"><BR>@if + exist "H:\Silent_Config.ffs_batch" (<BR></FONT><FONT COLOR="#808080"><FONT FACE="Courier New, monospace"><I><B>::configuration + found, now execute the synchronization batch job</B></I></FONT></FONT><FONT FACE="Courier New, monospace"><BR>"C:\Program + Files\FreeFileSync\FreeFileSync.exe" + "H:\Silent_Config.ffs_batch"<BR>@if not errorlevel 0 + (<BR></FONT><FONT COLOR="#808080"><FONT FACE="Courier New, monospace"><I><B>::if + something went wrong, start FreeFileSync in GUI + mode</B></I></FONT></FONT><FONT FACE="Courier New, monospace"><BR></FONT> <FONT FACE="Courier New, monospace">"C:\Program + Files\FreeFileSync\FreeFileSync.exe" + "H:\GUI_Config.ffs_gui"<BR>)<BR>)</FONT></P> </SPAN><BR CLEAR=LEFT> </P> </UL> +<P STYLE="margin-bottom: 0cm"><BR> +</P> </BODY> </HTML>
\ No newline at end of file diff --git a/BUILD/Help/html/advanced/RealtimeSync_html_72dda21b.gif b/BUILD/Help/html/advanced/RealtimeSync_html_72dda21b.gif Binary files differdeleted file mode 100644 index 9da1bc3f..00000000 --- a/BUILD/Help/html/advanced/RealtimeSync_html_72dda21b.gif +++ /dev/null diff --git a/BUILD/Help/html/advanced/ScheduleBatch.html b/BUILD/Help/html/advanced/ScheduleBatch.html index 4d1f3de0..bb956401 100644 --- a/BUILD/Help/html/advanced/ScheduleBatch.html +++ b/BUILD/Help/html/advanced/ScheduleBatch.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;16291600"> + <META NAME="CHANGED" CONTENT="20100118;18123600"> <STYLE TYPE="text/css"> <!-- @page { margin: 2cm } @@ -19,23 +19,22 @@ </HEAD> <BODY LANG="de-DE" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Schedule Batch -Job in Windows Task Planner (Windows XP)</FONT></H3> +Job in Windows Task Planner <SPAN STYLE="font-weight: normal">(Windows +XP)</SPAN></FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> <OL> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create a new batch job via FreeFileSync's main dialog:<BR><I>Menu->Advanced->Create batch job</I> and save - it, for example, as <FONT FACE="Courier New, monospace">"C:\SyncJob.ffs_batch</FONT>".</FONT></P> - <P STYLE="margin-bottom: 0cm"></P> + it, for example, as "<FONT FACE="Courier New, monospace">C:\SyncJob.ffs_ + batch</FONT>".</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Make - sure you are using "<I>silent mode</I>" to prevent showing - a status dialog at the end of the process.</FONT></P> - <P STYLE="margin-bottom: 0cm"></P> + sure you enable checkbox "<I>silent mode</I>" to prevent + showing a status dialog at the end of the process.</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Start Windows Task Scheduler: Go to <I>Start->Control Panel->Scheduled Tasks</I> and select "<I>Add Scheduled Task</I>".</FONT></P> - <P STYLE="margin-bottom: 0cm"></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Follow the wizard and choose "<FONT FACE="Courier New, monospace">C:\SyncJob.ffs_batch</FONT>" as program to run.</FONT></P> @@ -45,7 +44,6 @@ Job in Windows Task Planner (Windows XP)</FONT></H3> </FONT><FONT FACE="Courier New, monospace">*.ffs_batch</FONT> <FONT FACE="Tahoma, sans-serif">files are automatically associated with the tool and field "</FONT><FONT FACE="Tahoma, sans-serif"><I>Run:</I></FONT><FONT FACE="Tahoma, sans-serif">" can be filled with the filename directly:<BR>"</FONT><FONT FACE="Courier New, monospace">C:\SyncJob.ffs_batch</FONT><FONT FACE="Tahoma, sans-serif">"<BR><IMG SRC="scheduleBatch_html_m22c860a2.gif" NAME="Grafik1" ALIGN=BOTTOM WIDTH=406 HEIGHT=455 BORDER=0></FONT></P> - <P STYLE="margin-bottom: 0cm"></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">If file associations have not been set (portable/zip-version),</FONT> "<FONT FACE="Tahoma, sans-serif"><I>Run:</I></FONT><FONT FACE="Tahoma, sans-serif">" diff --git a/BUILD/Help/html/advanced/SendMail.html b/BUILD/Help/html/advanced/SendMail.html index 10ea0e4a..0946de2b 100644 --- a/BUILD/Help/html/advanced/SendMail.html +++ b/BUILD/Help/html/advanced/SendMail.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.0 (Win32)"> + <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.1 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;15581500"> + <META NAME="CHANGED" CONTENT="20091231;16373900"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -32,7 +32,7 @@ Batch Mode and send error notification via email</FONT></H3> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Set error handling to "<I>Exit with Returncode < 0</I>" or "<I>ignore errors</I>" to avoid having a popup stop the - program flow. In case errors occur FreeFileSync will abort with a + program flow. In case errors occur FreeFileSync will exit with a returncode < 0 which can be checked via the ERRORLEVEL batch command.</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create @@ -41,11 +41,12 @@ Batch Mode and send error notification via email</FONT></H3> e.g.:</FONT></P> </OL> <UL> - <P STYLE="margin-bottom: 0cm"><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> + <P><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> <UL> - <P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><FONT FACE="Courier New, monospace">C:\Program - Files\FreeFileSync\FreeFileSync.exe C:\SyncJob.ffs_batch<BR>if not - errorlevel 0 echo An error occured! && pause</FONT></P> + <P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><FONT FACE="Courier New, monospace">"C:\Program + Files\FreeFileSync\FreeFileSync.exe" + "C:\SyncJob.ffs_batch"<BR>@if not errorlevel 0 + (<BR> echo An error occured!<BR> pause<BR>)</FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> diff --git a/BUILD/Help/html/advanced/SymbolicLinks.html b/BUILD/Help/html/advanced/SymbolicLinks.html index e3dd6ea2..b85c6bbd 100644 --- a/BUILD/Help/html/advanced/SymbolicLinks.html +++ b/BUILD/Help/html/advanced/SymbolicLinks.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;16130900"> + <META NAME="CHANGED" CONTENT="20091213;19145800"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -56,10 +56,10 @@ being copied instead.</FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">"<I>TraverseDirectorySymlinks</I>" specifies handling of Symbolic Links to directories:</FONT></P> <P STYLE="margin-left: 2cm; margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">If -<I>true</I>, they are being traversed like ordinary directories -during comparison and are copied as if they were regular directories -(i.e. not as Symbolic Links) during synchronization.<BR>If <I>false</I> -is selected, these Symbolic Links are not traversed at all. During +<I>true</I>, they are being traversed like regular directories during +comparison and are copied as if they were regular directories (i.e. +not as Symbolic Links) during synchronization.<BR>If <I>false</I> is +selected, these Symbolic Links are not traversed at all. During synchronization copying them results in a direct copy of the Symbolic Link, not the target directory.</FONT></P> <P STYLE="margin-left: 2cm; margin-bottom: 0cm"><SPAN ID="Rahmen2" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: 1px solid #000080; padding: 0.05cm; background: #ccccff"> diff --git a/BUILD/Help/html/advanced/VariableDrive.html b/BUILD/Help/html/advanced/VariableDrive.html index e46bbaad..975995cf 100644 --- a/BUILD/Help/html/advanced/VariableDrive.html +++ b/BUILD/Help/html/advanced/VariableDrive.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091213;16011300"> + <META NAME="CHANGED" CONTENT="20091213;19170300"> <STYLE TYPE="text/css"> <!-- @page { margin: 2cm } @@ -37,9 +37,19 @@ the following workflow is possible:</FONT></P> the absolute USB directory name in your configuration by a relative one:<BR>E.g. "<FONT FACE="Courier New, monospace">E:\SyncDir</FONT>" -> "<FONT FACE="Courier New, monospace">\SyncDir</FONT>"</FONT></P> + <P STYLE="margin-bottom: 0cm"></P> + </OL> +</UL> +<UL> + <OL> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Save and copy synchronization settings to the USB stick: "<FONT FACE="Courier New, monospace">E:\settings.ffs_gui</FONT>"</FONT></P> + </OL> +</UL> +<UL> + <OL> + <P STYLE="margin-bottom: 0cm"></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Start FreeFileSync by double-clicking on "</FONT><FONT FACE="Courier New, monospace">E:\settings.ffs_gui</FONT><FONT FACE="Tahoma, sans-serif">"<BR>=> Working directory automatically is set to "</FONT><FONT FACE="Courier New, monospace">E:\</FONT><FONT FACE="Tahoma, sans-serif">" diff --git a/BUILD/Help/html/advanced/rts.png b/BUILD/Help/html/advanced/rts.png Binary files differnew file mode 100644 index 00000000..8462d0e0 --- /dev/null +++ b/BUILD/Help/html/advanced/rts.png diff --git a/BUILD/Help/html/advanced/rts23.png b/BUILD/Help/html/advanced/rts23.png Binary files differnew file mode 100644 index 00000000..9cda186d --- /dev/null +++ b/BUILD/Help/html/advanced/rts23.png diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng index d73d300c..1d7b11dc 100644 --- a/BUILD/Languages/chinese_simple.lng +++ b/BUILD/Languages/chinese_simple.lng @@ -46,6 +46,8 @@ å–消(&C) &Check for new version 检查更新(&C) +&Content +内容(&C) &Create batch job 创建批处ç†ä½œä¸š(&C) &Default @@ -88,6 +90,8 @@ 是(&Y) (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (请注æ„åªæœ‰FAT/FAT32分区å—æ¤é—®é¢˜å½±å“!\nåœ¨æ‰€æœ‰å…¶ä»–æƒ…å†µä¸‹ä½ å¯ç¦ç”¨\"忽略一å°æ—¶å·®å¼‚\"这一选项.) +(Requires an Internet connection!) +(需è¦å› 特网连接!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. 比较(&C) 1. Enter relative file or directory names separated by ';' or a new line. 1. 输入相对文件或文件夹å称,用';'或空行分隔. +1. Select directories to monitor. +1. 选择è¦ç›‘视的目录. 2. &Synchronize... 2. åŒæ¥(&S)... +2. Enter a command line. +2. 输入一个命令行. 2. Use wildcard characters '*' and '?'. 2. 使用通é…符‘*’和‘?’. 3. Exclude files directly on main grid via context menu. 3. 通过å³é”®èœå•åœ¨ä¸»ç½‘æ ¼æŽ’é™¤æ–‡ä»¶. +3. Press 'Start'. +3. 点击'开始'. <Automatic> 自动 <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if 顾åæ€ä¹‰,两个相åŒæ–‡ä»¶å的文件当且仅当它们具有相åŒçš„内容时会被认为是相åŒçš„。\næ¤é€‰é¡¹å¯¹äºŽä¸€è‡´æ€§æ£€æŸ¥æ¯”较有用,而ä¸æ˜¯å¤‡ä»½æ“作. å› æ¤,文件时间没有被考虑到. \n\n通过æ¤é€‰é¡¹ä½¿å†³ç–æ ‘è¾ƒå°: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. 装é…一个批处ç†æ–‡ä»¶ç”¨äºŽè‡ªåŠ¨åŒæ¥. è¦å¼€å§‹æ‰¹å¤„ç†æ¨¡å¼åªéœ€ç®€å•åœ°å°†æ‰¹å¤„ç†æ–‡ä»¶åä¼ é€ç»™FreeFileSyncå¯æ‰§è¡Œæ–‡ä»¶:FreeFileSync.exe <batchfile>. 这个也å¯ä»¥å®‰æŽ’在您的æ“作系统的计划任务ä¸. +At least one directory input field is empty. +至少有一个目录输入å—段是空的. Auto-adjust columns 自动调整æ 宽 Automatic mode @@ -192,20 +204,18 @@ Build: å¼€å‘: Cancel å–消 -Cannot determine sync-direction: Changed filter settings! -ä¸èƒ½ç¡®å®šåŒæ¥æ–¹å‘: 过滤器设置已改å˜! -Cannot determine sync-direction: No change since last synchronization! -ä¸èƒ½ç¡®å®šåŒæ¥æ–¹å‘: 在最åŽåŒæ¥ä¹‹åŽæ²¡æœ‰æ”¹å˜! +Cannot determine sync-direction: +ä¸èƒ½æ£€æµ‹åŒæ¥æ–¹å‘: Category 分类 Change direction 改å˜æ–¹å‘ Comma separated list 逗å·åˆ†éš”的列表 -Commandline +Command line 命令行 -Commandline is empty! -命令行为空! +Command line is empty! +命令行是空的! Compare 比较 Compare both sides @@ -260,8 +270,12 @@ Copy from right to left 从å³ä¾§å¤åˆ¶åˆ°å·¦ä¾§ Copy from right to left overwriting 从å³ä¾§å¤åˆ¶åˆ°å·¦ä¾§(覆盖模å¼) +Copy locked files +å¤åˆ¶è¢«é”定的文件 Copy new or updated files to right folder. å¤åˆ¶æ–°çš„或修改过的文件到å³ä¾§æ–‡ä»¶å¤¹ +Copy shared or locked files using Volume Shadow Copy Service. +使用å·å½±å¤åˆ¶æœåŠ¡æ¥å¤åˆ¶å…±äº«æˆ–é”定的文件. Copy to clipboard\tCTRL+C å¤åˆ¶åˆ°å‰ªè´´æ¿\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: ä¸èƒ½ç¡®å®šæ¤æ–‡ä»¶çš„å·å称: Could not initialize directory monitoring: ä¸èƒ½åˆå§‹åŒ–目录监视: +Could not load a required DLL: +ä¸èƒ½åŠ 载所需的动æ€è¿žæŽ¥åº“: Could not read values for the following XML nodes: ä¸èƒ½ä»Žå¦‚下XML节点读å–数值: Create a batch job @@ -298,7 +314,7 @@ Date 日期 Delay 延时 -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds 在检测和执行命令行之间的延时秒数 Delete files/folders existing on left side only åˆ é™¤ä»…åœ¨å·¦ä¾§å˜åœ¨çš„文件/文件夹 @@ -386,6 +402,8 @@ Error reading file: 读å–文件出错: Error reading from synchronization database: 从åŒæ¥æ•°æ®åº“ä¸è¯»å–时出错: +Error resolving full path name: +解决完整路径时出错: Error resolving symbolic link: 解决符å·é“¾æŽ¥å‡ºé”™: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files 过滤文件 Filter has been selected 过滤器已选择 +Filter settings have changed! +过滤设置已改å˜! Filter view 过滤查看 Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows 包括所有行 Include temporarily 暂时包括 -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -包括: *.doc;*.zip;*.exe\n排除temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +包括: *.doc;*.zip;*.exe\n排除\\stuff\\temp\\* Incompatible synchronization database format: ä¸å…¼å®¹çš„åŒæ¥æ•°æ®åº“æ ¼å¼: Info @@ -572,8 +592,6 @@ Initial synchronization: åˆå§‹åŒ–åŒæ¥: Integrate external applications into context menu. The following macros are available: 集æˆå¤–部应用程åºåˆ°å³é”®èœå•. 如下å®å¯ç”¨: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -åˆå§‹åŒ–回收站是ä¸å¤§å¯èƒ½äº†!\n\nä¼°è®¡ä½ ä½¿ç”¨çš„ä¸æ˜¯Windows系统.\nå¦‚æžœä½ æƒ³åŒ…å«æ¤ç‰¹æ€§,请è”系作者. :) Leave as unresolved conflict é—ç•™ä¸ºæœªè§£å†³çš„å†²çª Left @@ -590,18 +608,22 @@ Log-messages: 日志信æ¯: Logging 记录 +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +ä¸æ”¯æŒåœ¨WOW64上使用å·å½±å¤åˆ¶. 请使用 FreeFileSync 64ä½ç‰ˆæœ¬. Mirror ->> é•œåƒ ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. 左侧文件夹镜åƒå¤‡ä»½: åŒæ¥åŽå³ä¾§æ–‡ä»¶å¤¹å°†è¢«è¦†ç›–并且完全匹é…左边的文件夹. +Monitoring active... +监视激活... More than 50% of the total number of files will be copied or deleted! 超过总数 50% 以上的文件è¦è¢«å¤åˆ¶æˆ–åˆ é™¤! Move column down 下移一行 Move column up 上移一行 -Move files to a user-defined directory. -移动文件到用户定义的目录 +Move files into a time-stamped subdirectory. +ç§»åŠ¨æ–‡ä»¶åˆ°æ—¶é—´æ ‡è®°å目录. Moving %x to Recycle Bin 移动 %x 到回收站 Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y 移动文件夹 %x 到用户定义目录 %y Multiple... å€æ•°... +No change since last synchronization! +自从最åŽä¸€æ¬¡åŒæ¥ä»¥æ¥æ²¡æœ‰å˜åŠ¨! No filter selected 没有选定过滤器 Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause æš‚åœ Paused å·²æš‚åœ -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -请å¤åˆ¶é€‚当的\"Shadow.dll\"(ä½äºŽ\"Shadow.zip\"压缩包ä¸)到FreeFileSync安装目录以å¯ç”¨æ¤ç‰¹æ€§. -Please fill all empty directory fields. -请填满所有空的目录区域. Please run a Compare first before synchronizing! åŒæ¥ä¹‹å‰è¯·å…ˆè¿›è¡Œå¯¹æ¯” +Processing folder pair: +æ£åœ¨å¤„ç†æˆå¯¹æ–‡ä»¶å¤¹: Published under the GNU General Public License: 在GNU通用公共许å¯ä¸‹å‘布: Question @@ -670,6 +692,8 @@ Remove folder pair åˆ é™¤æ–‡ä»¶å¤¹å¯¹ Remove local filter settings 移除局部过滤器 +Renaming file %x to %y +å°† %x é‡å‘½å为 %y Report translation error 报告翻译错误 Reset @@ -786,6 +810,8 @@ Target directory already existing! ç›®æ ‡ç›®å½•å·²ç»å˜åœ¨! Target file already existing! ç›®æ ‡æ–‡ä»¶å·²ç»å˜åœ¨! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +命令行会被执行æ¯å½“:\n- 这些目录(或å目录)里é¢çš„文件有修改\n- 相应的盘符å˜æˆå¯ç”¨(æ’å…¥U盘) The database file is not yet existing, but will be created during synchronization: æ•°æ®åº“文件未å˜åœ¨, 但在åŒæ¥æœŸé—´ä¼šè¢«åˆ›å»º: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! æ— æ³•åˆ›å»ºæ—¥å¿—! Unable to initialize Recycle Bin! æ— æ³•åˆå§‹åŒ–回收站! +Unresolved conflicts existing! +å˜åœ¨ä¸å¯è§£å†³çš„冲çª! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. å˜åœ¨ä¸å¯è§£å†³çš„冲çª!\n\nä½ å¯å¿½ç•¥å†²çªå¹¶ç»§ç»åŒæ¥. Update -> å‡çº§ -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -用法: 选择è¦ç›‘视的目录并输入一命令行. æ¯æ¬¡ç›®å½•(或å目录)ä¸çš„文件被修改时æ¤å‘½ä»¤è¡Œå°±ä¼šæ‰§è¡Œ. +Usage: +用法: Use Recycle Bin 使用回收站 Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): è¦å‘Š:åŒæ¥å¤±è´¥ %x (æŸäº›)项目: When the comparison is started with this option set the following decision tree is processed: 当以æ¤é€‰é¡¹å¼€å§‹æ¯”è¾ƒæ—¶ä»¥ä¸‹å†³å®šæ ‘è¢«å¤„ç†: +You can ignore conflicts and continue synchronization. +ä½ å¯å¿½ç•¥å†²çªå¹¶ç»§ç»åŒæ¥. You can ignore the error to consider not existing directories as empty. 您å¯å¿½ç•¥æ¤é”™è¯¯è€Œå°†ä¸å˜åœ¨çš„目录视为空. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng index cc9abc57..d4e4e7b1 100644 --- a/BUILD/Languages/chinese_traditional.lng +++ b/BUILD/Languages/chinese_traditional.lng @@ -46,6 +46,8 @@ å–消(&C) &Check for new version 檢查更新(&C) +&Content +內容 &Create batch job 新建批次處ç†ä½œæ¥(&C) &Default @@ -87,7 +89,9 @@ &Yes 是 (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) -(請注æ„åªæœ‰ FAT/FAT32 ç£ç¢Ÿæ©Ÿæœƒå—到æ¤å•é¡Œçš„影響ï¼\n在所有其他狀æ³ä¸‹ï¼Œå¯ä»¥é—œé–‰é€™å€‹è¨å®š\"忽略1å°æ™‚的誤差"\。) +(請注æ„åªæœ‰ FAT/FAT32 ç£ç¢Ÿæ©Ÿæœƒå—到æ¤å•é¡Œçš„影響ï¼\n在所有其他狀æ³ä¸‹ï¼Œå¯ä»¥é—œé–‰é€™å€‹è¨å®š\"忽略1å°æ™‚的誤差\"。) +(Requires an Internet connection!) +(需è¦é€£æŽ¥åˆ°ç¶²éš›ç¶²è·¯ï¼) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. 比å°(&C) 1. Enter relative file or directory names separated by ';' or a new line. 1. 輸入相å°æª”案或目錄å稱,使用';'或空行分隔。 +1. Select directories to monitor. +1. é¸æ“‡è¦ç›£æ¸¬çš„目錄。 2. &Synchronize... 2. åŒæ¥(&S)... +2. Enter a command line. +2. 輸入命令列。 2. Use wildcard characters '*' and '?'. 2. 使用è¬ç”¨å—元‘*’和‘?’。 3. Exclude files directly on main grid via context menu. 3. 經由內容é¸å–®ç›´æŽ¥åœ¨ä¸»è¦ç¶²æ ¼æŽ’除檔案。 +3. Press 'Start'. +3. 按下 '開始'。 <Automatic> <自動> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if 顧åæ€ç¾©ï¼Œå…©å€‹ç›¸åŒæª”å的檔案,åªæœ‰ç•¶ä»–們具有åŒæ¨£çš„内容時會被判斷是相åŒçš„。\næ¤é¸é …å°æ–¼ä¸€è‡´æ€§æª¢æŸ¥æ¯”較有用,而ä¸æ˜¯å‚™ä»½æ“ä½œã€‚å› æ¤ï¼Œæª”案時間沒有列入考慮。\n\n啟用æ¤é¸é …使決ç–樹較å°ï¼š Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. 組åˆä¸€å€‹ç”¨æ–¼è‡ªå‹•åŒæ¥çš„批次檔。若è¦é–‹å§‹æ‰¹æ¬¡è™•ç†æ¨¡å¼ï¼Œåªéœ€ç°¡å–®çš„將批次檔å傳é€ç»™ FreeFileSync å¯åŸ·è¡Œæª”:FreeFileSync.exe <batchfile>。這個也å¯ä»¥å®‰æŽ’åœ¨ä½ çš„ä½œæ¥ç³»çµ±çš„計畫任務ä¸ã€‚ +At least one directory input field is empty. +至少有一個目錄輸入欄ä½æ˜¯ç©ºçš„。 Auto-adjust columns 自動調整欄寬 Automatic mode @@ -192,19 +204,17 @@ Build: 建立: Cancel å–消 -Cannot determine sync-direction: Changed filter settings! -ä¸èƒ½åˆ¤æ–·åŒæ¥æ–¹å‘:已更改篩é¸å™¨è¨å®šï¼ -Cannot determine sync-direction: No change since last synchronization! -ä¸èƒ½åˆ¤æ–·åŒæ¥æ–¹å‘:自上次åŒæ¥å¾Œï¼Œæ²’有更改éŽï¼ +Cannot determine sync-direction: +無法判斷åŒæ¥æ–¹å‘: Category 分類 Change direction æ”¹è®Šæ–¹å‘ Comma separated list 逗號分隔清單 -Commandline +Command line 命令列 -Commandline is empty! +Command line is empty! å‘½ä»¤åˆ—æ˜¯ç©ºçš„ï¼ Compare æ¯”å° @@ -260,8 +270,12 @@ Copy from right to left 從å³é‚Šè¤‡è£½åˆ°å·¦é‚Š Copy from right to left overwriting 從å³é‚Šè¤‡è£½åˆ°å·¦é‚Šè¦†è“‹æª”案 +Copy locked files +複製被鎖定的檔案 Copy new or updated files to right folder. 將新的或更新éŽçš„檔案複製到å³é‚Šçš„資料夾ä¸ã€‚ +Copy shared or locked files using Volume Shadow Copy Service. +使用å·å½±è¤‡è£½æœå‹™ä¾†è¤‡è£½å…±äº«æˆ–鎖定的檔案。 Copy to clipboard\tCTRL+C 複製到剪貼簿\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: 無法判斷æ¤æª”案的å·æ¨™å稱: Could not initialize directory monitoring: 無法åˆå§‹åŒ–目錄監測: +Could not load a required DLL: +無法載入一個所需的DLL: Could not read values for the following XML nodes: ç„¡æ³•è®€å– XML 之後節點的值: Create a batch job @@ -298,7 +314,7 @@ Date 日期 Delay å»¶é² -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds 檢測更改和執行命令列的延é²æ™‚間,以秒為單ä½ã€‚ Delete files/folders existing on left side only 刪除åªå˜åœ¨æ–¼å·¦é‚Šçš„檔案/資料夾 @@ -386,6 +402,8 @@ Error reading file: 讀å–檔案錯誤: Error reading from synchronization database: 讀å–åŒæ¥è³‡æ–™åº«éŒ¯èª¤ï¼š +Error resolving full path name: +完整路徑å稱解æžéŒ¯èª¤ï¼š Error resolving symbolic link: 解决符號連çµéŒ¯èª¤ï¼š Error starting Volume Shadow Copy Service! @@ -393,7 +411,7 @@ Error starting Volume Shadow Copy Service! Error traversing directory: éæ·ç›®éŒ„錯誤: Error when monitoring directories. -監測目錄錯誤: +監測目錄錯誤。 Error writing file attributes: 寫入檔案屬性錯誤: Error writing file: @@ -466,6 +484,8 @@ Filter files 篩é¸æª”案 Filter has been selected å·²é¸æ“‡ç¯©é¸å™¨ +Filter settings have changed! +篩é¸å™¨è¨å®šå·²æ›´æ”¹ï¼ Filter view 篩é¸æª¢è¦– Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows 包括所有行 Include temporarily 暫時包括 -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -包括:*.doc;*.zip;*.exe\n排除temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +包括:*.doc;*.zip;*.exe\n排除\\stuff\\temp\\* Incompatible synchronization database format: åŒæ¥è³‡æ–™åº«æ ¼å¼ä¸ç›¸å®¹ï¼š Info @@ -569,11 +589,9 @@ Info Information è¨Šæ¯ Initial synchronization: -åˆå§‹åŒ–åŒæ¥: +åˆå§‹åŒ–åŒæ¥ï¼š Integrate external applications into context menu. The following macros are available: æ•´åˆä¸Šä¸‹æ–‡åŠŸèƒ½è¡¨ä¸çš„外部應用程å¼ã€‚å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„巨集: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -ä¸èƒ½åˆå§‹åŒ–資æºå›žæ”¶ç’ï¼\n\nå¯èƒ½ä½ 使用的ä¸æ˜¯ Windows 系統。\nå¦‚æžœä½ æƒ³åŒ…æ‹¬æ¤åŠŸèƒ½ï¼Œè«‹è¯ç¹«ä½œè€…。:) Leave as unresolved conflict ä¿ç•™çµ¦æœªè§£æ±ºçš„è¡çª Left @@ -590,18 +608,22 @@ Log-messages: 日誌訊æ¯ï¼š Logging 日誌記錄 +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +ä¸æ”¯æ´è£½ä½œ WOW64 上的å·å½±å‰¯æœ¬ã€‚請使用 FreeFileSync 64ä½å…ƒç‰ˆæœ¬ã€‚ Mirror ->> é¡åƒ ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. -左邊資料夾的é¡åƒå‚™ä»½ï¼šåŒæ¥ä¹‹å¾Œï¼Œå³é‚Šè³‡æ–™å¤¾å°‡è¢«è¦†è“‹ï¼Œå®Œå…¨å’Œå·¦é‚Šè³‡æ–™å¤¾ä¸€æ¨¡ä¸€æ¨£ã€‚ +左邊資料夾的é¡åƒå‚™ä»½ï¼š åŒæ¥ä¹‹å¾Œï¼Œå³é‚Šè³‡æ–™å¤¾å°‡è¢«è¦†è“‹ï¼Œå®Œå…¨å’Œå·¦é‚Šè³‡æ–™å¤¾ä¸€æ¨¡ä¸€æ¨£ã€‚ +Monitoring active... +監測活動... More than 50% of the total number of files will be copied or deleted! 超éŽç¸½æ•¸ 50% ä»¥ä¸Šçš„æª”æ¡ˆå°‡è¢«è¤‡è£½æˆ–åˆªé™¤ï¼ Move column down 下移一行 Move column up 上移一行 -Move files to a user-defined directory. -將檔案移動到自定義目錄。 +Move files into a time-stamped subdirectory. +移動檔案到一個時間標記的å目錄。 Moving %x to Recycle Bin 移動 %x 到資æºå›žæ”¶ç’ Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y 移動資料夾 %x 到自定義資料夾 %y Multiple... 多個... +No change since last synchronization! +自上次åŒæ¥ä»¥ä¾†éƒ½æ²’æœ‰è®Šæ›´ï¼ No filter selected 沒有é¸æ“‡ç¯©é¸å™¨ Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause æš«åœ Paused å·²æš«åœ -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -請複製é©ç•¶çš„\"Shadow.dll\"(ä½æ–¼\"Shadow.zip\"壓縮檔)到 FreeFileSync 安è£ç›®éŒ„以啟用æ¤åŠŸèƒ½ã€‚ -Please fill all empty directory fields. -請填滿所有空白目錄欄ä½ã€‚ Please run a Compare first before synchronizing! 請執行åŒæ¥å‰å…ˆæ¯”å°ï¼ +Processing folder pair: +處ç†å…©å€‹è³‡æ–™å¤¾ï¼š Published under the GNU General Public License: 在GNU通用公共許å¯è‰ä¸‹ç™¼ä½ˆï¼š Question @@ -670,6 +692,8 @@ Remove folder pair 移除兩個資料夾 Remove local filter settings 移除局部性篩é¸å™¨è¨å®š +Renaming file %x to %y +檔案é‡æ–°å‘½å %x 為 %y Report translation error å›žå ±ç¿»è¯éŒ¯èª¤ Reset @@ -786,6 +810,8 @@ Target directory already existing! 目標目錄已å˜åœ¨ï¼ Target file already existing! 目標檔案已å˜åœ¨ï¼ +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +命令行æ¯æ¬¡åŸ·è¡Œæ™‚:\n- 檔案在這些目錄(或å目錄)會被修改\n- å¯ä¾›ä½¿ç”¨ç›¸æ‡‰çš„ç£ç¢Ÿæ©Ÿä»£è™Ÿ(USBæ’å…¥) The database file is not yet existing, but will be created during synchronization: 資料庫檔未å˜åœ¨ï¼Œä½†æœƒåœ¨åŒæ¥éŽç¨‹ä¸æ–°å»ºï¼š The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! ç„¡æ³•æ–°å»ºæ—¥èªŒæª”ï¼ Unable to initialize Recycle Bin! 無法åˆå§‹åŒ–資æºå›žæ”¶ç’ï¼ +Unresolved conflicts existing! +å˜åœ¨æœªè§£æ±ºçš„è¡çªï¼ Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. å˜åœ¨æœªè§£æ±ºçš„è¡çªï¼\n\nä½ å¯ä»¥å¿½ç•¥è¡çªï¼Œä¸¦ç¹¼çºŒåŒæ¥ã€‚ Update -> æ›´æ–° -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -用法:é¸æ“‡ç›£æ¸¬çš„目錄並輸入命令行。æ¯æ¬¡ç›®éŒ„(或å目錄)ä¸çš„檔案被修改時,æ¤å‘½ä»¤åˆ—就會執行。 +Usage: +使用é‡ï¼š Use Recycle Bin 使用資æºå›žæ”¶ç’ Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): è¦å‘Šï¼šåŒæ¥å¤±æ•—çš„å稱為 %x é …ç›®ï¼š When the comparison is started with this option set the following decision tree is processed: 當比å°é–‹å§‹ï¼Œä½¿ç”¨æ¤é¸é …è¨å®šæ™‚,以下決ç–樹將被處ç†ï¼š +You can ignore conflicts and continue synchronization. +ä½ å¯ä»¥å¿½ç•¥è¡çªï¼Œä¸¦ç¹¼çºŒåŒæ¥ã€‚ You can ignore the error to consider not existing directories as empty. ä½ å¯ä»¥å¿½ç•¥è©²éŒ¯èª¤è€Œå°‡ä¸å˜åœ¨çš„目錄視為空目錄。 You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng index 8be657b4..56778c7b 100644 --- a/BUILD/Languages/czech.lng +++ b/BUILD/Languages/czech.lng @@ -46,6 +46,8 @@ souborů: %x; &ZruÅ¡it &Check for new version Zkontrolovat &aktualizace +&Content +&Obsah &Create batch job &VytvoÅ™it dávku &Default @@ -88,6 +90,8 @@ U&konÄit &Ano (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Platà pouze pro souborové systémy FAT/FAT32. V ostatnÃch pÅ™Ãpadech můžete nastavenà \"Ignorovat 1 hodinu rozdÃlu v Äase mezi soubory\" nechat vypnuté.) +(Requires an Internet connection!) +(Vyžaduje pÅ™ipojenà k internetu!) , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ soubor: 1; 1. &Porovnat 1. Enter relative file or directory names separated by ';' or a new line. 1. Můžete použÃt relativnà cesty k souboru nebo adresáři oddÄ›lené ';' nebo řádkem. +1. Select directories to monitor. +1. Vyberte adresáře pro sledovánÃ. 2. &Synchronize... 2. &Synchronizovat... +2. Enter a command line. +2. Zadejte pÅ™Ãkazovou řádku. 2. Use wildcard characters '*' and '?'. 2. Můžete použÃt zástupné znaky (wildcard) '*' a '?'. 3. Exclude files directly on main grid via context menu. 3. Můžete použÃt pro vynechávánà souborů pÅ™Ãmo kontextového menu. +3. Press 'Start'. +3. ZmáÄknÄ›te 'Start' <Automatic> <Automaticky> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Jak název napovÃdá, dva soubory majÃcà stejné jméno jsou oznaÄeny za shodné jen a pouze pokud majà shodný obsah. Toto nastavenà je vhodné spÃÅ¡e pro sledovánà konzistence než pro zálohovánÃ. Proto nejsou data zmÄ›n souborů brána vůbec v potaz.\n\nPokud vyberete toto nastavenà bude schéma rozhodovánà kratÅ¡Ã: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. VytvoÅ™enà dávkového souboru pro automatický provoz. Ke spuÅ¡tÄ›nà dávky jednoduÅ¡e jejà jméno zadejte jako parametr pÅ™i spuÅ¡tÄ›nà FreeFileSync: FreeFileSync.exe <batchfile>. +At least one directory input field is empty. +Alespoň jedno zadánà adresáře je prázdné. Auto-adjust columns Automaticky pÅ™izpůsobit Å¡ÃÅ™ku Automatic mode @@ -192,19 +204,17 @@ Build: Build: Cancel ZruÅ¡it -Cannot determine sync-direction: Changed filter settings! -Nelze urÄit smÄ›r synchronizace: Změňte nastavenà filtru! -Cannot determine sync-direction: No change since last synchronization! -Nelze urÄit smÄ›r synchronizace: NedoÅ¡lo ke zmÄ›nám od poslednà synchronizace! +Cannot determine sync-direction: +Nelze urÄit smÄ›r synchronizace: Category Kategorie Change direction ZmÄ›nit akci Comma separated list Text oddÄ›lený Äárkami -Commandline +Command line PÅ™Ãkazová řádka -Commandline is empty! +Command line is empty! PÅ™Ãkazová řádka je prázdná! Compare Porovnat @@ -260,8 +270,12 @@ Copy from right to left KopÃrovat z prava do leva Copy from right to left overwriting KopÃrovat z prava do leva pÅ™episem +Copy locked files +KopÃrovat zamÄené soubory Copy new or updated files to right folder. KopÃrovat nové nebo aktualizované soubory do adresáře vpravo. +Copy shared or locked files using Volume Shadow Copy Service. +KopÃrovat sdÃlené nebo zamÄené soubory pomocà Volume Shadow Copy Service. Copy to clipboard\tCTRL+C Vložit do schránky\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Nenà možné zjistit jméno jednotky souboru: Could not initialize directory monitoring: Nelze nastavit monitorovánà adresáře: +Could not load a required DLL: +Nelze naÄÃst požadovanou knihovnu DLL: Could not read values for the following XML nodes: Nelze naÄÃst hodnoty následujÃcÃch XML elementy: Create a batch job @@ -298,7 +314,7 @@ Date Datum Delay ZpoždÄ›nà -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds ZpoždÄ›nà detekce zmÄ›n a spuÅ¡tÄ›nà pÅ™Ãkazu v sekundách Delete files/folders existing on left side only Smazat soubory/adresáře existujÃcà pouze na levé stranÄ› @@ -386,6 +402,8 @@ Error reading file: Chyba Ätenà souboru: Error reading from synchronization database: Chyba Ätenà synchronizaÄnà databáze: +Error resolving full path name: +Chyba názvu plné cesty: Error resolving symbolic link: Chyba odkazu zástupce: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtrovat soubory Filter has been selected Filtr je zapnut +Filter settings have changed! +Nastavenà filtru bylo zmÄ›nÄ›no! Filter view Filtrovat seznam Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows PoužÃt vÅ¡echny řádky Include temporarily PÅ™idat doÄasnÄ› -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -PÅ™idat: *.doc;*.zip;*.exe\nVynechat: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +PÅ™idat: *.doc;*.zip;*.exe\nVynechat: \\stuff\\temp\\* Incompatible synchronization database format: Chyba formátu synchronizaÄnà databáze: Info @@ -572,8 +592,6 @@ Initial synchronization: Prvotnà synchronizace: Integrate external applications into context menu. The following macros are available: Integrace externà aplikace do kontextového menu. K dispozici jsou následujÃcà makra: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Nebylo možné inicializovat KoÅ¡!\n\nPravdÄ›podobnÄ› nepoužÃváte Windows.\nPokud chcete tuto vlastnost využÃvat, kontaktujte autora. :) Leave as unresolved conflict Ponechat jako nevyÅ™eÅ¡ený konflikt Left @@ -590,18 +608,22 @@ Log-messages: Záznamy: Logging Zaznamenávánà +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Vytvářenà stÃnových kopÃà na WOW64 nenà podporováno. ProsÃm použijte 64 bitovou verzi FreeFileSync. Mirror ->> Zrcadlenà ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Zrcadlenà levého adresáře: Pravý adresář bude pÅ™epsán a po synchronizaci bude totožný s levým. +Monitoring active... +Sledovánà zapnuto... More than 50% of the total number of files will be copied or deleted! VÃce než 50% souborů bude kopÃrovaných nebo mazaných! Move column down PÅ™esunout sloupec dolů Move column up PÅ™esunout sloupec nahoru -Move files to a user-defined directory. -PÅ™esunout soubory do uživatelem definovaného adresáře. +Move files into a time-stamped subdirectory. +PÅ™esunout soubory do ÄasovÄ› oznaÄeného podadresáře. Moving %x to Recycle Bin PÅ™esouvánà %x do KoÅ¡e. Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y PÅ™esouvánà adresáře %x do uživatelského adresáře %y Multiple... NÄ›kolikanásobný... +No change since last synchronization! +Žádné zmÄ›ny od poslednà synchronizace! No filter selected Nenà vybrán žádný filtr Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pauza Paused Pauza -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -ProsÃm zkopÃrujte odpovÃdajÃcà \"Shadow.dll\" (umÃstÄ›ný v \"Shadow.zip\") do instalaÄnÃho adresáře FreeFileSync, aby bylo možné použÃt tuto funkci. -Please fill all empty directory fields. -Zadejte adresáře pro synchronizaci. Please run a Compare first before synchronizing! ProsÃm proveÄte nejdÅ™Ãv porovnánà pÅ™ed synchronizacÃ! +Processing folder pair: +Zpracovávánà adresářové páru: Published under the GNU General Public License: Vydáno podl GNU General Public License (GPL): Question @@ -670,6 +692,8 @@ Remove folder pair Odstranit dvojici adresářů Remove local filter settings Odstranit nastavenà mÃstnÃho filtru +Renaming file %x to %y +PÅ™ejmenovávánà souboru %x na %y Report translation error Hlásit chyby pÅ™ekladu Reset @@ -786,6 +810,8 @@ Target directory already existing! CÃlový adresář již existuje! Target file already existing! CÃlový soubor již existuje! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +PÅ™Ãkazová řádka je spuÅ¡tÄ›na pokaždé když:\n- dojde ke zmÄ›nÄ› souborů v adresáři (nebo podadresářÃch)\n- je pÅ™ipojen odpovÃdajÃcà disk (vloženÃm USB disku) The database file is not yet existing, but will be created during synchronization: Databáze jeÅ¡tÄ› neexistuje, ale bude bÄ›hem synchronizace vytvoÅ™ena: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! nenà možné vytvoÅ™it záznamový soubor! Unable to initialize Recycle Bin! Nenà možné použÃt KoÅ¡! +Unresolved conflicts existing! +NevyÅ™eÅ¡ené konflikty! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. NevyÅ™eÅ¡ené konflikty! \n\nJe možné konflikt ignorovat a pokraÄovat v synchronizaci. Update -> Aktualizuj -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -PoužitÃ: Vyberte adresáře, které majà být monitorovány a vložte pÅ™Ãkaz. Pokaždé, když dojde ke zmÄ›nÄ› v tÄ›chto adresářÃch (nebo podadresářÃch), bude pÅ™Ãkaz spuÅ¡tÄ›n. +Usage: +PoužitÃ: Use Recycle Bin PoužÃt KoÅ¡ Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): VarovánÃ: Synchronizace se nepovedla pro \"%x\" položek: When the comparison is started with this option set the following decision tree is processed: Když je zahájeno porovnávánà s tÃmto nastavenÃm, je použito následujÃcà schéma rozhodovánÃ: +You can ignore conflicts and continue synchronization. +Je možné konflikt ignorovat a pokraÄovat v synchronizaci. You can ignore the error to consider not existing directories as empty. Pro považovánà neexistujÃcÃch adresářů jako prázdných můžete chybu ignorovat. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng index c17049ba..0aaf8f61 100644 --- a/BUILD/Languages/dutch.lng +++ b/BUILD/Languages/dutch.lng @@ -46,6 +46,8 @@ &Annuleren &Check for new version &Controleer op nieuwe versie +&Content +&Help artikelen &Create batch job &Creëer batchjob &Default @@ -88,6 +90,8 @@ &Ja (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Alleen FAT/FAT32 schijven hebben last van dit probleem!\nIn alle andere gevallen kunt u deze instelling uitschakelen \"negeer 1-uur tijdsverschil\".) +(Requires an Internet connection!) +(Vereist een internetverbinding) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Vergelijk 1. Enter relative file or directory names separated by ';' or a new line. 1. Vul de relatieve bestandsnaam of map in, gescheiden bij ';' of een nieuwe regel. +1. Select directories to monitor. +1. Selecteer mappen om te observeren. 2. &Synchronize... 2. &Synchroniseer... +2. Enter a command line. +2. Geef een opdrachtregel in. 2. Use wildcard characters '*' and '?'. 2. U kunt gebruik maken van wildcard karakters zoals '*' en '?'. 3. Exclude files directly on main grid via context menu. 3. Sluit bestanden direct uit in het hoofscherm via een contextmenu +3. Press 'Start'. +3. Klik op 'Start'. <Automatic> <Automatisch> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Zoals de naam suggereert, worden twee bestanden met dezelfde naam alleen gemarkeerd als gelijk, als ze precies dezelfde inhoud hebben. Deze optie is handig voor een consistentiecontrole in plaats van back-up handelingen. Daarom worden de tijdstempels niet bekeken.\n\n Met deze optie aan is de beslissingsboom korter: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Assembleer een batchbestand voor automatische synchronisatie. Om te starten in batchmodus is het voldoende om de bestandsnaam achter de FreeFileSync toepassing te zetten: FreeFileSync.exe <batchbestand>. Het is mogelijk dit in te plannen in de systeemplanner. +At least one directory input field is empty. +Er is minimaal één locatie-veld leeg. Auto-adjust columns Kolommen automatisch aanpassen Automatic mode @@ -192,19 +204,17 @@ Build: Gebouwd: Cancel Annuleren -Cannot determine sync-direction: Changed filter settings! -Kan de synchronisatie-richting niet bepalen: verandering in -Cannot determine sync-direction: No change since last synchronization! -Kan de synchronisatie-richting niet bepalen: geen verandering sinds de laatste synchronisatie! +Cannot determine sync-direction: +Kan de synchronisatie-richting niet bepalen: Category Categorie Change direction Zijdes omwisselen Comma separated list Komma gescheiden lijst -Commandline +Command line Opdrachtregel -Commandline is empty! +Command line is empty! Opdrachtregel is leeg! Compare Vergelijk @@ -260,8 +270,12 @@ Copy from right to left Kopieer van rechts naar links Copy from right to left overwriting Kopieer en overschrijf van rechts naar links +Copy locked files +Kopieer 'alleen lezen' bestanden Copy new or updated files to right folder. Kopieer nieuwe of geupdate bestanden naar de rechter map. +Copy shared or locked files using Volume Shadow Copy Service. +Kopieer gedeelde of alleen-lezen bestanden met Volume Shadow Copy Service. Copy to clipboard\tCTRL+C Kopieer naar het klembord\tCTRL+C Copying file %x to %y @@ -271,7 +285,9 @@ Aan het overschrijven van bestand %x naar %y Could not determine volume name for file: Kon de schijfnaam niet vaststellen van bestand: Could not initialize directory monitoring: -Initaliseren van locatie-controle niet mogelijk: +Initaliseren van locatie-observatie niet mogelijk: +Could not load a required DLL: +Kon een benodigde DLL niet laden: Could not read values for the following XML nodes: Kon geen waarden inlezen voor de volgende XML punten: Create a batch job @@ -298,7 +314,7 @@ Date Datum Delay Vertraging -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Vertraging tussen detecteren van veranderingen en uitvoering van de opdrachtregel in seconden Delete files/folders existing on left side only Verwijder bestanden/folders die alleen links bestaan @@ -386,6 +402,8 @@ Error reading file: Er is een fout opgetreden bij het lezen van het bestand: Error reading from synchronization database: Er is een fout opgetreden bij het lezen van de synchronisatie-database: +Error resolving full path name: +Er is een fout opgetreden bij het ophalen van de locatie van bestand: Error resolving symbolic link: Er is een fout opgetreden bij het ophalen van een symbolische koppeling: Error starting Volume Shadow Copy Service! @@ -393,7 +411,7 @@ Er is een fout opgetreden bij het starten van de Volume Schadow Copy Service! Error traversing directory: Er is een fout opgetreden bij het doorzoeken van map: Error when monitoring directories. -Er is een fout opgetreden bij het controleren van locaties. +Er is een fout opgetreden bij het observeren van locaties. Error writing file attributes: Er is een fout opgetreden bij het schrijven van de bestands-eigenschappen: Error writing file: @@ -466,6 +484,8 @@ Filter files Filter bestanden Filter has been selected Filter is geselecteerd +Filter settings have changed! +Filter instellingen opgeslagen! Filter view Bekijk het filter Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Alle rijen gebruiken Include temporarily Tijdelijk bijsluiten -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Bijsluiten: *.doc;*.zip;*.exe\nUitsluiten: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Bijsluiten: *.doc;*.zip;*.exe\nUitsluiten: \\stuff\\temp\\* Incompatible synchronization database format: Opmaak van synchronisatie-database komt niet overeen: Info @@ -572,8 +592,6 @@ Initial synchronization: Initiële synchronisatie: Integrate external applications into context menu. The following macros are available: Integreer externe applicaties in het context menu. De volgende macros zijn beschikbaar: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Het was niet mogelijk de prullenbak te initialiseren!\n\nHet is waarschijnlijk dat u niet Windows gebruikt.\nAls u deze optie wel wilt, neem dan alstublieft contact op met de auteur. :) Leave as unresolved conflict Beschouwen als onopgelost conflict Left @@ -590,18 +608,22 @@ Log-messages: Logberichten: Logging Loggen +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Schaduw kopieen op WOW64 worden niet ondersteund. Gebruik alstublieft de 64-bit versie van FreeFileSync. Mirror ->> Spiegelen ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Spiegel backup van de linkerkant: de rechterkant wordt overschreven en komt na synchronisatie exact overeen met de linkerkant. +Monitoring active... +Observeren actief... More than 50% of the total number of files will be copied or deleted! Meer dan 50% van alle bestanden zal worden gekopieerd of verwijderd! Move column down Verplaats kolom naar beneden Move column up Verplaats kolom naar boven -Move files to a user-defined directory. -Verplaats bestanden naar een door de gebruiker te definiëren map. +Move files into a time-stamped subdirectory. +Verplaats de bestanden in een tijd-gemarkeerde sublocatie. Moving %x to Recycle Bin %x aan het verplaatsen naar de Prullenbak Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Verplaatsen map %x naar een door de gebruiker gedefinieerde locatie %y Multiple... Meerdere... +No change since last synchronization! +Geen veranderingen sinds de laatste synchronisatie! No filter selected Geen filter geselecteerd Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pause Paused Gepauseerd -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Kopiëer alstublieft \"Shadow.dll\" (locatie in \"Shadow.zip\" archief) naar de FreeFileSync installatiemap om het gebruik van deze optie mogelijk te maken -Please fill all empty directory fields. -Vul alstublieft aan beide kanten een pad in. Please run a Compare first before synchronizing! Voer eerst een Vergelijking uit voordat u synchroniseerd. +Processing folder pair: +Verwerken van gekoppelde folder: Published under the GNU General Public License: Gepubliceerd onder de GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair Verwijder 1 paar gekoppelde mappen Remove local filter settings Verwijder lokale filter instellingen +Renaming file %x to %y +Hernoemen van bestand %x naar %y Report translation error Rapporteer een fout in de vertaling Reset @@ -786,6 +810,8 @@ Target directory already existing! Doellocatie bestaal al! Target file already existing! Doelbestand bestaat al! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +De opdrachtregel wordt elke keer uitgevoerd als:\n- Bestanden in deze folders (of subfolders) zijn gewijzigd\n- De gekoppelde schijf beschikbaar wordt (USB-invoegen) The database file is not yet existing, but will be created during synchronization: Database-bestand bestaat nog niet, maar zal worden aangemaakt tijdens het synchroniseren: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Niet mogelijk om een logbestand aan te maken! Unable to initialize Recycle Bin! De prullenbak kon niet worden geïnitialiseerd! +Unresolved conflicts existing! +Er bestaan onopgeloste conflicten! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Er bestaan onopgeloste conflicten! \n\nU kunt de conflicten negeren en doorgaan met synchroniseren. Update -> Overschrijven -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Uitleg: Selecteer locaties om te controleren en type een opdrachtregel. Elke keer dat bestanden worden aangepast binnen die locaties (en/of sublocaties) wordt de opdrachtregel uitgevoerd. +Usage: +Gebruik: Use Recycle Bin Gebruik de prullenbak Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Let op: %x item(s) konden niet worden gesynchroniseerd: When the comparison is started with this option set the following decision tree is processed: Wanneer met deze optie aan de vergelijking wordt gestart zal de volgende vergelijkingsboom worden gebruikt: +You can ignore conflicts and continue synchronization. +U kunt de conflicten negeren en doorgaan met synchroniseren. You can ignore the error to consider not existing directories as empty. U kunt de fout negeren om niet bestaande locaties als leeg te beschouwen. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng index d4b45c04..f988eed6 100644 --- a/BUILD/Languages/finnish.lng +++ b/BUILD/Languages/finnish.lng @@ -46,6 +46,8 @@ &Lopeta &Check for new version Etsi &uusi versio +&Content + &Create batch job &Tee eräajo &Default @@ -88,6 +90,8 @@ Asetusten &lataus &Kyllä (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (HUOM: Tämä ongelma vaikuttaa vain FAT/FAT32 ohjaimiin!\nOptio voidaan poistaa kaikissa muissa tapauksissa \"jätetään 1. tunnin ero huomiotta\".) +(Requires an Internet connection!) + , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ Asetusten &lataus 1. &Vertaa 1. Enter relative file or directory names separated by ';' or a new line. 1. Anna tiedostojen tai hakemistojen suhteelliset nimet eroteltuina ';' tai rivivaihto +1. Select directories to monitor. + 2. &Synchronize... 2. &Täsmäytä... +2. Enter a command line. + 2. Use wildcard characters '*' and '?'. 2. Käytä jokerimerkkejä '*' ja '?' . 3. Exclude files directly on main grid via context menu. 3. Sulje tiedostoja pois suoraan pääikkunassa viite hakemiston avulla. +3. Press 'Start'. + <Automatic> <- Automaattinen -> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Nimensä mukaisesti, tiedostot joilla on sama nimi, merkitään samoiksi vain jos niiden sisältö täsmää. Ominaisuus soveltuu paremmin yhdenpitävyyden tarkistukseen kuin varmistukseen. Siksi tiedostojen aikaleimaa ohitetaan.\n\nPäätöksentekopuu on tästä syystä pienempi: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Luo automaattiseen täsmäytykseen eräajon komentotiedosto. Käynnistä eräajo liittämällä FreeFileSyn ohjelmalle komentotiedosto: FreeFileSync.exe <eräajotiedosto>. Tehtävän suoritusta voit ajoittaa käyttöjärjestelmän toimilla. +At least one directory input field is empty. + Auto-adjust columns Säädä sarakeleveys automaattisesti Automatic mode @@ -192,20 +204,18 @@ Build: Luotu: Cancel Keskeytä -Cannot determine sync-direction: Changed filter settings! -Täsmäytys suunta on tuntematon: Muuta suodatusasetuksia! -Cannot determine sync-direction: No change since last synchronization! -Täsmäytys suunta on tuntematon: Ei muutoksia viimeisestä täsmäytyksestä! +Cannot determine sync-direction: + Category Luokka Change direction Vaihda suunta Comma separated list CSV-muotoinen lista -Commandline +Command line Komentokehote -Commandline is empty! -Tyhjä komentokehote! +Command line is empty! + Compare Vertaile Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Kopioidaan oikea -> vasen Copy from right to left overwriting Kopioidaan oikea -> vasen ylikirjoittaen +Copy locked files + Copy new or updated files to right folder. Kopioidaan uudet tai muuttuneet tiedostot oikeaan hakemistoon. +Copy shared or locked files using Volume Shadow Copy Service. + Copy to clipboard\tCTRL+C Kopioi Leikepöydälle\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Levyasemaa ei tunnistettu tiedostolle: Could not initialize directory monitoring: Ei voitu käynnistää hakemiston tarkkailua: +Could not load a required DLL: + Could not read values for the following XML nodes: Tietoja lukeminen epäonnistui, XML jäsen: Create a batch job @@ -298,7 +314,7 @@ Date Päiväys Delay Viive -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Viive sekunneissa havaitun muutoksen ja komentokehotteen suorittamisen välillä Delete files/folders existing on left side only Poista vain tiedostoja/hakemistoja vasemmalta @@ -386,6 +402,8 @@ Error reading file: Virhe lukiessa tiedostoa: Error reading from synchronization database: Virhe lukiessa täsmäytyksen tietokantaa: +Error resolving full path name: + Error resolving symbolic link: Virhe selvittäessä symbolista linkkiä: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Suodata tiedostoja Filter has been selected Suodin valittu +Filter settings have changed! + Filter view Näytä suodattimet Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Sisällytä kaikki rivit Include temporarily Sisällytä tilapäisesti -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Sisällytä: *.doc;*.zip;*.exe\nSulje pois: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Sisällytä: *.doc;*.zip;*.exe\nSulje pois: \\stuff\\temp\\* Incompatible synchronization database format: Täsmäytyksen tietokannan muoto on virheellinen: Info @@ -572,8 +592,6 @@ Initial synchronization: Ensi täsmäytys: Integrate external applications into context menu. The following macros are available: Liitä ulkoinen sovellus viitekehysvalikkoon. Seuraavat makrot ovat valittavissa: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Roskakorin alustus epäonnistui!\n\nIlmeisesti et käytä Microsoft Windowsia.\nJos haluat liittää tämän toiminnon, ota yhteyttä tekijää. :) Leave as unresolved conflict Jätä ratkaisemattomana virheenä Left @@ -590,18 +608,22 @@ Log-messages: Lokin viestit: Logging Kirjaa +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. + Mirror ->> Peilaava ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Vasemman hakemiston varmuuskopio: Oikea ylikirjoitetaan ja on täsmäytyksen jälkeen vasemman tarkka kopio. +Monitoring active... + More than 50% of the total number of files will be copied or deleted! Enemmän kuin 50% tiedostoista kopioidaan tai poistetaan! Move column down Siirrä sarake alas Move column up Siirrä sarake ylös -Move files to a user-defined directory. -Tiedostojen siirto valittuun hakemistoon +Move files into a time-stamped subdirectory. + Moving %x to Recycle Bin Siirrä %x Roskakoriin Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Siirrä hakemisto %x valittuun hakemistoon %y Multiple... Moninkertainen... +No change since last synchronization! + No filter selected Suodin valitsematta Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Tauko Paused Pysäytetty -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Kopioi tiedosto \"Shadow.dll\" (tiedostossa \"Shadow.zip\") FreeFileSync asennushakemistossa. -Please fill all empty directory fields. -Täytä kaikki tyhjät hakemistokentät. Please run a Compare first before synchronizing! Aja tarkistus ennen täsmäytystä. +Processing folder pair: + Published under the GNU General Public License: Julkaistu lisenssillä GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair Poista hakemistopari Remove local filter settings Poista paikalliset suotimet +Renaming file %x to %y + Report translation error Ilmoita käännösvirheestä Reset @@ -786,6 +810,8 @@ Target directory already existing! Haluttu tiedosto on jo olemassa! Target file already existing! Kohde tiedosto on jo olemassa! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) + The database file is not yet existing, but will be created during synchronization: Tietokanta puuttuu, luodaan täsmäytyksen aikana. The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Lokitiedostoa ei pystytä luomaan! Unable to initialize Recycle Bin! Roskakorin initialisointi ei onnistu! +Unresolved conflicts existing! + Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Ristiriita sovittamatta! \n\nVoit ohittaa ristiriita ja jatkaa täsmäytystä. Update -> Päivittävä -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Käyttö: Valitse hakemistot ja aseta komento. Jos tiedostojen sisältö muuttuu (myös alihakemistot) suoritetaan komento. +Usage: + Use Recycle Bin Käytä Roskakoria Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Varoitus: täsmäytys epäonnistui %x kohdassa: When the comparison is started with this option set the following decision tree is processed: Käynnistäessä täsmäytystä näillä asetuksilla ottaa käyttöön tämä päätöspuu: +You can ignore conflicts and continue synchronization. + You can ignore the error to consider not existing directories as empty. Sivuta virhe ja kohtele puuttuvat hakemistot tyhjinä. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng index ad91f136..bae3af5d 100644 --- a/BUILD/Languages/french.lng +++ b/BUILD/Languages/french.lng @@ -46,6 +46,8 @@ &Annuler &Check for new version &Rechercher une nouvelle version +&Content +&Contenu &Create batch job &Créer un fichier de commandes &Default @@ -88,6 +90,8 @@ &Oui (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Notez que seuls les lecteurs FAT/FAT32 sont touchées par ce problème ! \ NDans les autres cas, vous pouvez désactiver le paramètre \ "ignorer la différence d'une heure \".) +(Requires an Internet connection!) +(Nécessite une connexion internet) , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Comparer 1. Enter relative file or directory names separated by ';' or a new line. 1. Entrez les noms relatifs des fichiers ou des répertoires séparés par un ';' ou par un passage à la ligne. +1. Select directories to monitor. +1. Sélectionner les répertoires à surveiller. 2. &Synchronize... 2. &Synchroniser... +2. Enter a command line. +2. Entrez une ligne de commande. 2. Use wildcard characters '*' and '?'. 2. Les caractères génériques '*' et '?' sont acceptés. 3. Exclude files directly on main grid via context menu. 3. Exclure les fichiers directement sur le tableau principal à l'aide du menu contextuel. +3. Press 'Start'. +3. Cliquez sur 'Démarrer'. <Automatic> <Automatique> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Comme le nom le suggère, deux fichiers qui ont le même nom sont considérés comme identiques si, et seulement si, leur contenu est identique. Cette option est utile pour les contrôles de cohérence plutôt que pour les opérations de sauvegarde. Toutefois, les dates et heures ne sont pas du tout prises en compte.\n\nAvec cette option, l'arbre de décision est plus simple : Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Créer un fichier de commandespour une synchronisation automatique. Pour démarrer en mode batch, indiquer le nom du fichier à l'exécutable FreeFileSync : freefilesync.exe <fichier de commandes>. Ceci peut aussi être programmé dans le plannificateur de tâches. +At least one directory input field is empty. +Au moins un champ répertoire est vide. Auto-adjust columns Auto-ajustement des colonnes Automatic mode @@ -192,20 +204,18 @@ Build: Créé le : Cancel Annuler -Cannot determine sync-direction: Changed filter settings! -Impossible de déterminer le sens de la synchro : la configuration a été modifiée ! -Cannot determine sync-direction: No change since last synchronization! -Impossible de déterminer le sens de la synchro : Aucune modification depuis la dernière synchro ! +Cannot determine sync-direction: +Impossible de déterminer le sens de la synchro : Category Catégorie Change direction Changer la direction Comma separated list Liste d'éléments séparés par une virgule -Commandline +Command line Ligne de commande -Commandline is empty! -ligne de commande vide +Command line is empty! +La ligne de commande est vide ! Compare Comparer Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Copie de droite à gauche Copy from right to left overwriting Copie de droite à gauche avec remplacement +Copy locked files +Copier les fichiers verrouilés Copy new or updated files to right folder. Copie de fichiers nouveaux ou modifiés dans le dossier de droite. +Copy shared or locked files using Volume Shadow Copy Service. +Copier les fichiers partagés ou verrouilés en utilisant le service Volume Shadow Copy Copy to clipboard\tCTRL+C Copier dans le presse-papiers\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Impossible de trouver le nom de volume pour le fichier : Could not initialize directory monitoring: Impossible d'initialiser la surveillance des dossiers: +Could not load a required DLL: +Impossible de charger une DLL : Could not read values for the following XML nodes: Impossible de lire les valeurs des noeuds XML suivants : Create a batch job @@ -298,7 +314,7 @@ Date Date Delay délai -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Intervalle entre la détection des changements et l'exécution de la ligne de commande en secondes Delete files/folders existing on left side only Suppression des fichiers/répertoires n'existant que sur le côté gauche @@ -386,6 +402,8 @@ Error reading file: Erreur lors de la lecture du fichier : Error reading from synchronization database: Erreur lors de la lecture de la base de données de synchro : +Error resolving full path name: +Erreur lors de la résolution du chemin : Error resolving symbolic link: Erreur lors de la résolution du lien symbolique : Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtrage des fichiers Filter has been selected Le filtre a été sélectionné +Filter settings have changed! +La configuration du filtre a changé ! Filter view Filtrage de la vue Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Inclure toutes les lignes Include temporarily Inclure temporairement -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Inclure : *.doc;*.zip;*.exe\nExclure : temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Inclure : *.doc;*.zip;*.exe\nExclure : \\stuff\\temp\\* Incompatible synchronization database format: Format de la base de données de synchro incompatible : Info @@ -572,8 +592,6 @@ Initial synchronization: Première synchronisation: Integrate external applications into context menu. The following macros are available: Inclure les applications externes dans le menu contextuel. Les macros suivantes sont disponibles : -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Impossible d'accéder à la corbeille !\n\nIl est probable que vous n'utilisez pas Windows.\nSi vous désirez utilisee cette fonctionnalité, veuillez contacter l'auteur. :) Leave as unresolved conflict Abandonner en tant que conflit non résolu Left @@ -590,18 +608,22 @@ Log-messages: Messages log : Logging Connexion +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La copie en tâche de fond sur WOW64 n'est pas possible. Utilisez pour cela la version 64 bits de FreeFileSync. Mirror ->> Mirroir ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Sauvegarde miroir du répertoire de gauche : Le répertoire de droite sera écrasé et exactement identique au répertoire de gauche après la synchronisation. +Monitoring active... +Surveillance en cours... More than 50% of the total number of files will be copied or deleted! Plus de 50% des fichiers seront copiés ou détruits ! Move column down Déplacer la colonne vers le bas Move column up Déplacer la colonne vers le haut -Move files to a user-defined directory. -Déplacer les fichiers vers un répertoire défini par l'utilisateur. +Move files into a time-stamped subdirectory. +Déplacer les fichiers vers un sous-répertoire daté. Moving %x to Recycle Bin Déplacement de %x vers la Corbeille Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Déplacement du dossier %x vers le répertoire défini par l'utilisateur %y Multiple... Multiple... +No change since last synchronization! +Aucun changement depuis la dernière synchronisation ! No filter selected Aucun filtre sélectionné Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pause Paused En pause -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Veuillez copier le fichier \"Shadow.dll\" (situé dans l'archive \"Shadow.zip\") vers le répertoire d'installation de FreeFileSync pour utiliser cette fonctionnalité. -Please fill all empty directory fields. -Veuillez remplir tous les champs vides du répertoire. Please run a Compare first before synchronizing! Veuillez cliquer sur "Compareré avant de lancer la synchronisation ! +Processing folder pair: +Traitement de la paire de dossiers : Published under the GNU General Public License: Publié sous la licence GNU General Public : Question @@ -670,6 +692,8 @@ Remove folder pair Supprimer le couple de dossiers Remove local filter settings Supprimer la configuration du filtre local +Renaming file %x to %y +Renommage des fichiers %x en %y Report translation error Etat d'erreurs de transfert Reset @@ -786,6 +810,8 @@ Target directory already existing! Le répertoire de destination existe déjà ! Target file already existing! Le fichier de destination existe déjà ! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +La ligne de commande est exécutée chque fois que :\n- Les fichiers de ces répertoires (ou sous-répertoires sont modifiés\n- La lettre correspondant au disque devient accessible (insertion USB) The database file is not yet existing, but will be created during synchronization: La base de données n'existe pas encore, mais elle sera créée pendant la synchronisation : The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Impossible de créer un fichier log ! Unable to initialize Recycle Bin! Impossible d'initialiser la corbeille ! +Unresolved conflicts existing! +Il y a des conflits non résolus ! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Il y a des conflits non résolus !\n\nVous pouvez ignorer ces conflits et continuer la synchronisation. Update -> Mise à Jour -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Utilisation : Choisir un dossier et entrer une ligne de commande. A chaque fois qu'un fichier est modifié dans ces dossiers (ou sous-dossiers), la ligne de commande est éxécutée. +Usage: +Utilisation : Use Recycle Bin Utilisation de la corbeille Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Attention : La synchronisation a échouée pour %x élément(s) : When the comparison is started with this option set the following decision tree is processed: Lorsque la comparaison démarre avec cette option, l'arbre de décision suivant est exécuté : +You can ignore conflicts and continue synchronization. +Vous pouvez ignorer ces conflits et continuer la synchronisation. You can ignore the error to consider not existing directories as empty. Vous pouvez ignorer l'erreur considérant qu'un dossier inexistant est vide. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng index 552019ed..cc82a8ad 100644 --- a/BUILD/Languages/german.lng +++ b/BUILD/Languages/german.lng @@ -90,6 +90,8 @@ Konfiguration &laden &Ja (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Achtung: Nur FAT/FAT32 Laufwerke sind von diesem Problem betroffen!\nIn allen anderen Fällen kann die Einstellung \"Zeitunterschied von einer Stunde ignorieren\" deaktiviert werden.) +(Requires an Internet connection!) +(Eine Internetverbindung wird benötigt!) , . - Other side's counterpart to %dir @@ -134,12 +136,18 @@ Konfiguration &laden 1. &Vergleichen 1. Enter relative file or directory names separated by ';' or a new line. 1. Relative Datei- oder Verzeichnisnamen getrennt durch ';' oder eine Neuzeile eingeben. +1. Select directories to monitor. +1. Zu überwachende Verzeichnisse wählen. 2. &Synchronize... 2. &Synchronisieren... +2. Enter a command line. +2. Eine Befehlszeile angeben. 2. Use wildcard characters '*' and '?'. 2. Die Platzhalter '*' und '?' werden unterstützt. 3. Exclude files directly on main grid via context menu. 3. Dateien können direkt über das Kontextmenü im Hauptfenster ausgeschlossen werden. +3. Press 'Start'. +3. 'Start' drücken. <Automatic> <Automatik> <Directory> @@ -174,8 +182,10 @@ As the name suggests, two files which share the same name are marked as equal if Wie der Name andeutet, werden zwei Dateien mit gleichem Namen genau dann als gleich angesehen, wenn sie den gleichen Dateiinhalt haben. Diese Einstellung ist eher für Konsistenzprüfungen geeignet als für Backup-Operationen. Aus diesem Grund wird der Zeitpunkt der letzten Änderung der Dateien nicht berücksichtigt.\n\nDer Entscheidungsbaum ist in diesem Fall kleiner: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Erzeuge eine Batchdatei für die automatisierte Synchronisation. Um den Batch-Modus zu starten, muss nur der Dateiname an die Programmdatei übergeben werden: FreeFileSync.exe <Batchdatei>. Dies kann auch in den Taskplaner des Betriebssystems eingetragen werden. +At least one directory input field is empty. +Mindestens ein Verzeichniseingabefeld ist leer. Auto-adjust columns -Spalten automatisch anpassen +Spalten automatisch ausrichten Automatic mode Automatik Modus Batch execution @@ -194,19 +204,17 @@ Build: Build: Cancel Abbrechen -Cannot determine sync-direction: Changed filter settings! -Synchronisationsrichtung konnte nicht bestimmt werden: Filtereinstellungen wurden geändert! -Cannot determine sync-direction: No change since last synchronization! -Synchronisationsrichtung konnte nicht bestimmt werden: Keine Änderungen seit der letzten Synchronisation! +Cannot determine sync-direction: +Die Synchronisationsrichtung konnte nicht bestimmt werden: Category Kategorie Change direction Richtung ändern Comma separated list Kommagetrennte Liste -Commandline +Command line Befehlszeile -Commandline is empty! +Command line is empty! Die Befehlszeile ist leer! Compare Vergleichen @@ -266,6 +274,8 @@ Copy locked files Gesperrte Dateien kopieren Copy new or updated files to right folder. Neue oder aktualisierte Dateien vom linken in das rechte Verzeichnis kopieren. +Copy shared or locked files using Volume Shadow Copy Service. +Gesperrte oder gemeinsam verwendete Dateien mit Hilfe des Volume Shadow Copy Service kopieren. Copy to clipboard\tCTRL+C In die Zwischenablage kopieren\tCTRL+C Copying file %x to %y @@ -304,7 +314,7 @@ Date Datum Delay Verzögerung -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Verzögerung zwischen Erkennen einer Änderung und Aufrufen der Befehlszeile in Sekunden Delete files/folders existing on left side only Nur links existierende Dateien/Verzeichnisse löschen @@ -392,6 +402,8 @@ Error reading file: Fehler beim Lesen der Datei: Error reading from synchronization database: Fehler beim Lesen der Synchronisationsdatenbank: +Error resolving full path name: +Fehler beim Ermitteln des vollen Pfadnamens: Error resolving symbolic link: Fehler beim Auflösen des Symbolischen Links: Error starting Volume Shadow Copy Service! @@ -472,6 +484,8 @@ Filter files Dateien filtern Filter has been selected Filter ist ausgewählt +Filter settings have changed! +Die Filtereinstellungen wurden geändert! Filter view Ansicht filtern Filtering is deactivated @@ -566,8 +580,8 @@ Include all rows Alle Zeilen einschließen Include temporarily Temporär einschließen -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Einschließen: *.doc;*.zip;*.exe\nAusschließen: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Einschließen: *.doc;*.zip;*.exe\nAusschließen: \\stuff\\temp\\* Incompatible synchronization database format: Inkompatibles Datenbankformat: Info @@ -578,8 +592,6 @@ Initial synchronization: Erstmalige Synchronisation: Integrate external applications into context menu. The following macros are available: Integriert externe Anwendungen in das Kontextmenu. Die folgenden Makros stehen zur Verfügung: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Die Papierkorbfunktion steht nicht zur Verfügung!\n\nWahrscheinlich benutzen Sie nicht Microsoft Windows.\nWenn Sie diese Funktion wirklich benötigen, kontaktieren Sie bitte den Autor. :) Leave as unresolved conflict Als unbehandelten Konflikt belassen Left @@ -596,18 +608,22 @@ Log-messages: Protokollmeldungen: Logging Protokoll +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Das Erstellen von Schattenkopien unter WOW64 wird nicht unterstützt. Bitte benutzen Sie die FreeFileSync 64-Bit Version. Mirror ->> Spiegeln ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Spiegelkopie des linken Verzeichnisses erstellen: Das rechte Verzeichnis wird dabei überschrieben und nach der Synchronisation dem linken exakt entsprechen. +Monitoring active... +Ãœberwachung aktiv... More than 50% of the total number of files will be copied or deleted! Mehr als 50% aller Dateien werden kopiert oder gelöscht! Move column down Spalte nach unten verschieben Move column up Spalte nach oben verschieben -Move files to a user-defined directory. -Verschiebe Dateien in benutzerdefiniertes Verzeichnis +Move files into a time-stamped subdirectory. +Verschiebe Dateien in ein Unterverzeichnis mit Zeitstempel. Moving %x to Recycle Bin Verschiebe %x in den Papierkorb Moving file %x to user-defined directory %y @@ -616,6 +632,8 @@ Moving folder %x to user-defined directory %y Verschiebe Ordner %x in benutzerdefiniertes Verzeichnis %y Multiple... Verschiedene... +No change since last synchronization! +Keine Änderungen seit der letzten Synchronisation! No filter selected Kein Filter ausgewählt Not enough free disk space available in: @@ -648,10 +666,10 @@ Pause Pause Paused Angehalten -Please fill all empty directory fields. -Bitte die leeren Verzeichnisfelder füllen. Please run a Compare first before synchronizing! Vor der Synchronisation bitte zuerst einen Vergleich ausführen! +Processing folder pair: +Verarbeite Verzeichnispaar: Published under the GNU General Public License: Veröffentlicht unter der GNU General Public License: Question @@ -674,6 +692,8 @@ Remove folder pair Verzeichnispaar entfernen Remove local filter settings Lokale Filtereinstellungen entfernen +Renaming file %x to %y +Benenne Datei %x um nach %y Report translation error Ãœbersetzungsfehler melden Reset @@ -682,8 +702,6 @@ Right Rechts Run minimized and write status information to a logfile Minimiert ausführen und Statusinformationen in eine Logdatei schreiben -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Das Erstellen von Schattenkopien unter WOW64 wird nicht unterstützt. Bitte benutzen Sie die FreeFileSync 64-Bit Version. S&ave configuration Konfiguration s&peichern S&witch view @@ -792,6 +810,8 @@ Target directory already existing! Zielverzeichnis existiert bereits! Target file already existing! Die Zieldatei existiert bereits! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +Die Befehlszeile wird ausgeführt wenn:\n- Dateien innerhalb dieser Verzeichnisse (oder Unterverzeichnisse) geändert werden\n- der zugehörige Laufwerksbuchstabe verfügbar wird (USB-Anschluss) The database file is not yet existing, but will be created during synchronization: Die Datenbankdatei existiert noch nicht, wird jedoch während der Synchronisation erzeugt werden: The file does not contain a valid configuration: @@ -822,18 +842,18 @@ Unable to create logfile! Die Protokolldatei konnte nicht erstellt werden! Unable to initialize Recycle Bin! Der Papierkorb konnte nicht initialisiert werden! +Unresolved conflicts existing! +Es existieren ungelöste Konflikte! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Es existieren ungelöste Konflikte! \n\nDie Konflikte können ignoriert und die Synchronisation fortgesetzt werden. Update -> Aktualisieren -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Verwendung: Die zu überwachenden Verzeichnisse auswählen und eine Befehlszeile angeben. Jedesmal wenn Dateien innerhalb dieser Verzeichnisse (oder Unterverzeichnisse) verändert werden, wird die Befehlszeile ausgeführt. +Usage: +Verwendung: Use Recycle Bin Papierkorb verwenden Use Recycle Bin when deleting or overwriting files. Papierkorb für zu löschende oder zu überschreibende Dateien nutzen. -Use Volume Shadow Copy Service to copy locked or shared files. -Verwende den Volume Shadow Copy Service um gesperrte oder gemeinsam verwendete Dateien zu kopieren. User-defined directory Benutzerdefiniertes Verzeichnis User-defined directory for deletion was not specified! @@ -850,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Warnung: Synchronisation fehlgeschlagen für %x Element(e): When the comparison is started with this option set the following decision tree is processed: Wenn der Vergleich mit dieser Option gestartet wurde, wird folgender Entscheidungsbaum abgearbeitet: +You can ignore conflicts and continue synchronization. +Die Konflikte können ignoriert und die Synchronisation fortgesetzt werden. You can ignore the error to consider not existing directories as empty. Dieser Fehler kann ignoriert werden, um nicht existierende Verzeichnisse als leer anzusehen. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/hungarian.lng b/BUILD/Languages/hungarian.lng index ea6fccaa..b2d32ead 100644 --- a/BUILD/Languages/hungarian.lng +++ b/BUILD/Languages/hungarian.lng @@ -46,6 +46,8 @@ A(z) %x nem megfelelÅ‘ FreeFileSync kötegelt feladat fájl! &Mégsem &Check for new version &Új verzió keresése +&Content +&Tartalom &Create batch job &Kötegelt feladat létrehozása &Default @@ -88,6 +90,8 @@ A(z) %x nem megfelelÅ‘ FreeFileSync kötegelt feladat fájl! &Igen (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Megjegyzés: Csak a FAT/FAT32 meghajtókat érinti ez a probléma!\nMinden más esetben ki lehet kapcsolni az \"1 órás különbség figyelmen kÃvül hagyása\" beállÃtást.) +(Requires an Internet connection!) +(Internetkapcsolat szükséges!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ A(z) %x nem megfelelÅ‘ FreeFileSync kötegelt feladat fájl! 1. &ÖsszehasonlÃtás 1. Enter relative file or directory names separated by ';' or a new line. 1. A relatÃv fájl- és mappanevek megadása pontosvesszÅ‘vel elválasztva vagy új sorban. +1. Select directories to monitor. +1. Válaszd ki a figyelendÅ‘ mappákat. 2. &Synchronize... 2. &Szinkronizálás +2. Enter a command line. +2. Add meg a parancssort. 2. Use wildcard characters '*' and '?'. 2. A csillag ('*') és a kérdÅ‘jel ('?') helyettesÃtÅ‘ karakterek megengedettek. 3. Exclude files directly on main grid via context menu. 3. Fájlok közvetlen kizárása a fÅ‘ listából helyi menü segÃtségével. +3. Press 'Start'. +3. Nyomd meg a Start gombot. <Automatic> <Automatikus> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Ahogy a neve is mutatja, két fájl, melyeknek ugyanaz a nevük, akkor és csakis akkor lesz egyezÅ‘ként jelölve, ha a tartalmuk megegyezik. Ez az opció leginkább a konzisztencia-viszgálatokhoz jó, mintsem a biztonsági mentésekhez. Ãgy a fájlok dátuma nem számÃt semmit.\n\nEnnek az opciónak az engedélyezésével a döntési fa kisebb lesz: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Egy kötegelt feladat fájl létrehozása az automatizált szinkronizációhoz. Kötegelt feladat módban való indÃtáshoz egyszerűen meg kell adni a fájl nevét a FreeFileSync.exe-nek: FreeFileSync.exe <kötegelt feladat fájl>. Ezt ütemezni is lehet az operációs rendszer feladatkezelÅ‘jével. +At least one directory input field is empty. +Legalább az egyik mappa beviteli mezÅ‘ üres. Auto-adjust columns Oszlopok automatikus igazÃtása Automatic mode @@ -192,19 +204,17 @@ Build: Build: Cancel Mégsem -Cannot determine sync-direction: Changed filter settings! -Nem lehet meghatározni a szinkronizáció irányát: A szűrÅ‘beállÃtások megváltoztak! -Cannot determine sync-direction: No change since last synchronization! -Nem lehet meghatározni a szinkronizáció irányát: Nem volt változás az utolsó szinkronizáció óta! +Cannot determine sync-direction: +Nem lehet meghatározni a szinkronizáció irányát: Category Kategória Change direction Irány megváltoztatása Comma separated list Comma separated values -Commandline +Command line Parancssor -Commandline is empty! +Command line is empty! A parancssor üres! Compare ÖsszehasonlÃtás @@ -260,8 +270,12 @@ Copy from right to left Másolás a jobb oldalról a bal oldalra Copy from right to left overwriting Másolás a jobb oldalról a bal oldalra felülÃrással +Copy locked files +Zárolt fájlok másolása Copy new or updated files to right folder. Új vagy frissÃtett fájlok másolása a jobb oldali mappába. +Copy shared or locked files using Volume Shadow Copy Service. +Megosztott vagy zárolt fájlok másolása a Volume Shadow Copy Service segÃtségével. Copy to clipboard\tCTRL+C Másolás a vágólapra\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: A következÅ‘ fájlnak nem lehet meghatározni a kötetnevét: Could not initialize directory monitoring: A mappafigyelés inicializálása sikertelen: +Could not load a required DLL: +A szükséges DLL betöltése sikertelen: Could not read values for the following XML nodes: A következÅ‘ XML-csomópontok értékének beolvasása sikertelen: Create a batch job @@ -298,7 +314,7 @@ Date Dátum Delay Várakozás -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds A változások észlelése és a parancssor meghÃvása közötti várakozás másodpercben Delete files/folders existing on left side only Csak a bal oldalon létezÅ‘ fájlok/mappák törlése @@ -386,6 +402,8 @@ Error reading file: A fájl olvasása sikertelen: Error reading from synchronization database: Hiba történt a szinkronizációs adatbázis olvasása közben: +Error resolving full path name: +A teljes útvonal feloldása sikertelen: Error resolving symbolic link: A szimbolikus link feloldása sikertelen: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Fájlok szűrése Filter has been selected SzűrÅ‘ kiválasztva +Filter settings have changed! +A szűrÅ‘beállÃtások megváltoztak! Filter view SzűrÅ‘ nézet Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Minden sort csatolni Include temporarily Ideiglenesen csatolni -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Csatol: *.doc;*.zip;*.exe\nKizár: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Csatol: *.doc;*.zip;*.exe\nKizár: \\stuff\\temp\\* Incompatible synchronization database format: Inkompatibilis szinkronizációs adatbázis formátum: Info @@ -572,8 +592,6 @@ Initial synchronization: ElsÅ‘ szinkronizáció: Integrate external applications into context menu. The following macros are available: KülsÅ‘ alkalmazás integrálása a helyi menübe. Az elérhetÅ‘ makrók a következÅ‘k: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Lehetetlen a Lomtár (Recycle Bin) inicializálása!\n\nValószÃnűleg azért, mert nem Windost használ.\nHa szeretné ezt a funkciót használni, kérjük, lépjen kapcsolatba a szerzÅ‘vel. :) Leave as unresolved conflict Feloldatlan ütközésként hagyni Left @@ -590,18 +608,22 @@ Log-messages: Naplóbejegyzések: Logging Naplózás +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +A Shadow Copy a WOW64-en nem támogatott. Kérjük, használja a 64-bites FreeFileSync-et. Mirror ->> Tükrözés ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. A bal oldali mappa tükrözött másolata: A jobb oldali mappa felülÃródik és pontosan megegyezik majd a bal oldalival a szinkronizálás után. +Monitoring active... +Figyelés aktÃv... More than 50% of the total number of files will be copied or deleted! Az összes fájl több mint 50%-a másolva vagy törölve lesz! Move column down Oszlop mozgatása lefelé Move column up Oszlop mozgatása felfelé -Move files to a user-defined directory. -Fájlok mozgatása a felhasználó által megadott mappába. +Move files into a time-stamped subdirectory. +Fájlok másolása idÅ‘bélyeggel ellátott almappába. Moving %x to Recycle Bin %x mozgatása a Lomtárba Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y %x mappa mozgatása a felhasználó által megadott %y mappába Multiple... SokszorosÃtás +No change since last synchronization! +Az utolsó szinkronizálás után nem történt változás. No filter selected Nincs szűrÅ‘ kiválasztva Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Szünet Paused Szüneteltetve -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Ennek a funkciónak a használatához, kérjük, másold a megfelelÅ‘ \"Shadow.dll\" fájlt (megtalálható a \"Shadow.zip\" archÃvumban) abba a mappába, amelybe a FreeFileSync-et telepÃtetted. -Please fill all empty directory fields. -Kérjük, töltse ki az összes üres mappa mezÅ‘t. Please run a Compare first before synchronizing! Kérjük, futtass le egy összehasonlÃtást mielÅ‘tt szinkronizálnál! +Processing folder pair: +Mappapár feldolgozása: Published under the GNU General Public License: Kiadva a GNU General Public License alatt: Question @@ -670,6 +692,8 @@ Remove folder pair Mappa párok eltávolÃtása Remove local filter settings Lokális szűrÅ‘beállÃtások eltávolÃtása +Renaming file %x to %y +%x fájl átnevezése %y névre Report translation error FordÃtói hiba bejelentése Reset @@ -786,6 +810,8 @@ Target directory already existing! A célmappa már létezik! Target file already existing! A célként megadott fájl már létezik! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +A parancssor minden egyes alkalommal végrehajtódik, ha:\n- a megadott mappákban (vagy almappákban) lévÅ‘ fájlok megváltoznak\n- a megfelelÅ‘ meghajtójel elérhetÅ‘vé válik (USB-csatolás) The database file is not yet existing, but will be created during synchronization: Az adatbázisfájl nem létezik, de létre lesz hozva a szinkronizáció folyamán: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Nem lehet létrehozni a naplófájlt! Unable to initialize Recycle Bin! Nem lehet inicializálni a Lomtárat (Recycle Bin)! +Unresolved conflicts existing! +Feloldatlan ütközések vannak! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Feloldatlan ütközések vannak! \n\nFigyelmen kÃvül hagyhatod az ütközéseket és folytathatod a szinkronizálást. Update -> FrissÃtés -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Használat: Válassza ki a figyelendÅ‘ mappákat és adjon meg egy parancssort. Minden alkalommal, amikor az adott mappákon (vagy almappákon) belül megváltoznak a fájlok, a parancssor végrehajtásra kerül. +Usage: +Használat: Use Recycle Bin Lomtár (Recycle Bin) használata Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Figyelem: A következÅ‘ %x elem szinkronizálása sikertelen: When the comparison is started with this option set the following decision tree is processed: Ha az összehasonlÃtás ezekkel a beállÃtásokkal lesz elindÃtva, akkor a következÅ‘ döntési fa érvényesül: +You can ignore conflicts and continue synchronization. +Figyelmen kÃvül hagyhatod az ütközéseket és folytathatod a szinkronizálást. You can ignore the error to consider not existing directories as empty. Figyelmen kÃvül hagyhatja a hibákat a nem létezÅ‘ mappákat üresnek tekintve. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng index 22e85097..df56ba46 100644 --- a/BUILD/Languages/italian.lng +++ b/BUILD/Languages/italian.lng @@ -46,6 +46,8 @@ &Annulla &Check for new version &Controlla la presenza di nuove versioni +&Content +&Contenuto &Create batch job &Crea un job in batch &Default @@ -88,6 +90,8 @@ &Si (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Solo volumi con file-system FAT/FAT32 risentono di questo problema!\nIn tutti gli altri casi puoi disabilitare l'impostazione \"ignora differenze di 1 ora\".) +(Requires an Internet connection!) +(Richiede una connessione Internet!) , , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Compara 1. Enter relative file or directory names separated by ';' or a new line. 1. Inserisci i nomi relativi di file o directory separati da ';' o su una nuova riga. +1. Select directories to monitor. +1. Seleziona cartelle da monitorare. 2. &Synchronize... 2. &Sincronizza... +2. Enter a command line. +2. Inserisci linea di comando. 2. Use wildcard characters '*' and '?'. 2. Sono ammessi i caratteri generici '*' e '?'. 3. Exclude files directly on main grid via context menu. 3. Escludi i file direttamente sulla griglia principale tramite il menu contestuale. +3. Press 'Start'. +3. Premi 'Start'. <Automatic> <Automatico> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Come suggerisce il nome, due file con lo stesso nome sono considerati come identici se, e solamente se, il loro contenuto è identico. Questa opzione è utile sia per i contrlli di coerenza che per le operazioni di backup. Tuttavia, data e ora vengono ignorate.\n\nAbilitando questa opzione l'albero delle decisioni è semplificato: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Componi un file batch per la sincronia automatica. Per partire in modalità batch fai semplicemente seguire il nome del file all'eseguibile di FreeFileSync: FreeFileSync.exe <nomefilebatch>. Puoi anche schedulare l'operazione nelle operazioni pianificate del sistema operativo. +At least one directory input field is empty. +Almeno un campo di inserimento cartella e' vuoto. Auto-adjust columns Larghezza automatica colonne Automatic mode @@ -192,20 +204,18 @@ Build: Build: Cancel Annulla -Cannot determine sync-direction: Changed filter settings! -Impossibile determinare direzione di sincronia: Impostazioni filtro cambiate! -Cannot determine sync-direction: No change since last synchronization! -Impossibile determinare direzione di sincronia: Nessuna modifica dall'ultima sincronizzazione! +Cannot determine sync-direction: +Impossibile determinare direzione di sincronia: Category Categoria Change direction Cambia direzione Comma separated list Lista di elementi separati da virgola -Commandline +Command line Linea di comando -Commandline is empty! -La linea di comando è vuota! +Command line is empty! +Linea di comando e' vuota! Compare Compara Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Copia da destra a sinistra Copy from right to left overwriting Copia da destra a sinistra sovrascrivendo +Copy locked files +Copia file bloccati Copy new or updated files to right folder. Copia file nuovi o aggiornati nella cartella di destra. +Copy shared or locked files using Volume Shadow Copy Service. +Copia file condivisi o bloccati usando il servizio Volume Shadow Copy Copy to clipboard\tCTRL+C Copia nella clipboard\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Impossibile determinare il nome volume per il file: Could not initialize directory monitoring: Monitoraggio directory non inizializzabile: +Could not load a required DLL: +Impossibile caricare una DLL richiesta: Could not read values for the following XML nodes: Impossibile leggere i valori per i seguenti nodi XML: Create a batch job @@ -298,8 +314,8 @@ Date Data Delay Ritardo -Delay between detection of changes and execution of commandline in seconds -Ritardo in secondi tra rilevazione cambiamenti ed esecuzione della commandline +Delay between detection of changes and execution of command line in seconds +Ritardo in secondi tra rilevazione cambiamenti ed esecuzione della command line Delete files/folders existing on left side only Elimina files/cartelle esistenti solo a sinistra Delete files/folders existing on right side only @@ -386,6 +402,8 @@ Error reading file: Errore durante la lettura del file: Error reading from synchronization database: Errore in lettura dal database di sincronizzione: +Error resolving full path name: +Errore nella risoluzione del nome di percorso completo: Error resolving symbolic link: Errore nella risoluzione di collegamento simbolico: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtro dei files Filter has been selected Filtro selezionato +Filter settings have changed! +Le impostazioni del filtro sono cambiate! Filter view Filtro della vista Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Includi tutte le righe Include temporarily Includi temporaneamente -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Includi: *.doc;*.zip;*.exe\nEscludi: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Includi: *.doc;*.zip;*.exe\nEscludi: \\stuff\\temp\\* Incompatible synchronization database format: Formato database di sincronizzazione incompatibile: Info @@ -572,8 +592,6 @@ Initial synchronization: Prima sincronizzazione: Integrate external applications into context menu. The following macros are available: Integra applicazioni esterne nel menu contestuale. Sono disponibili le seguenti macro: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Impossibile inizializzare il Cestino!\n\nE'probabile che non si stia utilizzando Windows.\nSe si vuole usare questa funzionalità , contattare l'autore. :) Leave as unresolved conflict Lascia come conflitti irrisolti Left @@ -590,18 +608,22 @@ Log-messages: Log-messages: Logging Logging +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La creazione di copie shadow su WOW64 non e' supportata. Utilizzare FreeFileSync in versione 64-bit. Mirror ->> Mirror ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Mirror backup della cartella di sinistra: La cartella di destra sarà sovrascritta e resa identica alla cartella di sinistra dopo la sincronizzazione. +Monitoring active... +Monitoraggio attivo... More than 50% of the total number of files will be copied or deleted! Piu' del 50% del totale dei files saranno copiati o cancellati! Move column down Sposta colonna giu' Move column up Sposta colonna su' -Move files to a user-defined directory. -Sposta i file in una directory personalizzata. +Move files into a time-stamped subdirectory. +Sposta file in una sotto-cartella datata. Moving %x to Recycle Bin Spostamento di %x nel Cestino Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Spostamento di cartella %x nella directory personalizzata %y Multiple... Multiplo... +No change since last synchronization! +Nessun cambiamento dall'ultima sincronizzazione! No filter selected Nessun filtro selezionato Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pausa Paused In pausa -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Per abilitare questa funzione è necessario copiare l'appropriata \"Shadow.dll\" (che si trova nell'archivio \"Shadow.zip\") nella directory di installazione di FreeFileSync. -Please fill all empty directory fields. -Compilare tutti i campi di directory vuoti. Please run a Compare first before synchronizing! Prima di sincronizzare effettua una Comparazione! +Processing folder pair: +Elaborazione coppia di cartelle: Published under the GNU General Public License: Pubblicato sotto licenza GNU General Public: Question @@ -670,6 +692,8 @@ Remove folder pair Elimina la coppia di cartelle Remove local filter settings Rimuovi impostazioni di filtro locale +Renaming file %x to %y +Rinomina file %x in %y Report translation error Segnala errori di traduzione Reset @@ -786,6 +810,8 @@ Target directory already existing! Directory di destinazione già esistente! Target file already existing! File destinazione già esistente! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +La linea di comando e' eseguita ogni volta che:\n- I file in queste cartelle (o sottocartelle) sono modificati\n- La corrispondente unita' disco e' disponibile (inserimento USB) The database file is not yet existing, but will be created during synchronization: Il database non e' ancora esistente, ma verra' creato durante la sincronizzazione: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Impossibile creaer il file di log! Unable to initialize Recycle Bin! Impossibile inizializzare il Cestino! +Unresolved conflicts existing! +Sono presenti conflitti irrisolti! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Sono presenti conflitti irrisolti! \n\nPuoi ignorare i conflitti e continuare la sincronizzazione. Update -> Aggiorna -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Uso: Seleziona le directory da monitorare e inserisci una linea di comando. Ogni volta che i file vengono modificati in queste directory (o sotto-directory) la linea di comando verrà eseguita. +Usage: +Uso: Use Recycle Bin Usa il Cestino Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Attenzione: Sincronizzazione fallita per %x elementi: When the comparison is started with this option set the following decision tree is processed: Quando questo set di opzioni viene selezionato per la comparazione viene processato il seguente albero di decisioni: +You can ignore conflicts and continue synchronization. +Puoi ignorare i conflitti e continuare la sincronizzazione. You can ignore the error to consider not existing directories as empty. Puoi ignorare l'errore per considerare directory inesistenti come vuote. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng index ff52cff2..f6a81d65 100644 --- a/BUILD/Languages/japanese.lng +++ b/BUILD/Languages/japanese.lng @@ -46,6 +46,8 @@ ã‚ャンセル(&C) &Check for new version ãƒãƒ¼ã‚¸ãƒ§ãƒ³æ›´æ–°ã®ç¢ºèª(&C) +&Content +トピック(&C) &Create batch job 一括ジョブを作æˆ(&C) &Default @@ -88,6 +90,8 @@ ã¯ã„(&Y) (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (注æ„: FAT/FAT32 ドライブã®ã¿ã“ã®å½±éŸ¿ã‚’å—ã‘ã¾ã™! \n ãã®ä»–ã®ã‚±ãƒ¼ã‚¹ã§ã¯è¨å®šã‚’無効ã«ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"1 時間ã®å·®ç•°ã¯ç„¡è¦–" ) +(Requires an Internet connection!) +(インターãƒãƒƒãƒˆæŽ¥ç¶šã‚’å¿…è¦ã¨ã—ã¾ã™!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. 比較(&C) 1. Enter relative file or directory names separated by ';' or a new line. 1. 相対ファイルã€ã¾ãŸã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’ ';' ã¾ãŸã¯ 改行ã§åŒºåˆ‡ã£ã¦å…¥åŠ› +1. Select directories to monitor. +1. 監視ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’é¸æŠž 2. &Synchronize... 2. åŒæœŸå‡¦ç†(&S)... +2. Enter a command line. +2. コマンドラインを入力 2. Use wildcard characters '*' and '?'. 2. ワイルドカード㫠' * ' 㨠' ? ' を使用出æ¥ã¾ã™ã€‚ 3. Exclude files directly on main grid via context menu. 3. コンテã‚ストメニューã‹ã‚‰ç›´æŽ¥ãƒ•ã‚¡ã‚¤ãƒ«ã‚’除外出æ¥ã¾ã™ã€‚ +3. Press 'Start'. +3. 'スタート'をクリック <Automatic> <自動> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if ã“ã®ã‚ªãƒ—ションã§ã¯ã€åŒã˜åå‰ã‚’共有ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã§å†…容ãŒåŒã˜å ´åˆã¯ã€åŒä¸€ã¨ã—ã¦æ‰±ã‚ã‚Œã¾ã™ã€‚ ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—æ“作よりã€ã‚€ã—ã‚æ•´åˆæ€§ã®ãƒã‚§ãƒƒã‚¯ã‚’è¡Œã†æ™‚ã«å½¹ç«‹ã¤ã‚ªãƒ—ションã§ã™ã€‚ 従ã£ã¦ãƒ•ã‚¡ã‚¤ãƒ«ã®æ—¥æ™‚ã«ã¤ã„ã¦ã¯å…¨ã考慮ã•ã‚Œã¦ã„ã¾ã›ã‚“。\n\nè¨å®šãŒæœ‰åŠ¹ãªæ™‚ã¯ã€ãƒ„リー表示ãŒå°ã•ããªã‚Šã¾ã™ã€‚ Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. 一括ã§åŒæœŸå‡¦ç†ã‚’è¡Œã†ãŸã‚ã®ãƒãƒƒãƒãƒ•ã‚¡ã‚¤ãƒ«ã‚’作æˆã—ã¾ã™ã€‚ 一括モードを開始ã™ã‚‹ã¨ãã¯ã€ãƒ•ã‚¡ã‚¤ãƒ«ã®ãƒ‘スåを実行ファイル\n< FreeFileSync.exe> \nã«ãƒãƒƒãƒãƒ•ã‚¡ã‚¤ãƒ«ã§æ¸¡ã™ã ã‘ã§ã™ã€‚ ã¾ãŸã€ã“ã®æ“作ã¯OSã®ã‚¿ã‚¹ã‚¯ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ©ã‹ã‚‰å®Ÿè¡Œã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +At least one directory input field is empty. +å°‘ãªãã¨ã‚‚ã²ã¨ã¤ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’é¸æŠžã—ã¦ãã ã•ã„ Auto-adjust columns 列ã®è‡ªå‹•èª¿æ•´ Automatic mode @@ -192,19 +204,17 @@ Build: ビルド: Cancel ä¸æ¢ -Cannot determine sync-direction: Changed filter settings! -åŒæœŸæ–¹å‘を決定ã§ãã¾ã›ã‚“: フィルターè¨å®šãŒå¤‰æ›´ã•ã‚Œã¦ã„ã¾ã™! -Cannot determine sync-direction: No change since last synchronization! -åŒæœŸæ–¹å‘を決定ã§ãã¾ã›ã‚“: å‰å›žæœ€å¾Œã®åŒæœŸå‡¦ç†ä»¥é™ã€å¤‰æ›´ã¯ã‚ã‚Šã¾ã›ã‚“ +Cannot determine sync-direction: +åŒæœŸæ–¹å‘ãŒæ±ºå®šã•ã‚Œã¦ã„ã¾ã›ã‚“: Category カテゴリ Change direction æ–¹å‘を変更 Comma separated list カンマ区切り -Commandline +Command line コマンドライン -Commandline is empty! +Command line is empty! コマンドラインãŒç©ºç™½ã§ã™! Compare 比較 @@ -260,8 +270,12 @@ Copy from right to left å³ã‹ã‚‰å·¦ã«ã‚³ãƒ”ー Copy from right to left overwriting å³ã‹ã‚‰å·¦ã«ä¸Šæ›¸ãコピー +Copy locked files +ãƒãƒƒã‚¯ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピー Copy new or updated files to right folder. æ–°ã—ã„(æ›´æ–°)ファイルをå³ãƒ•ã‚©ãƒ«ãƒ€ã«ã‚³ãƒ”ー +Copy shared or locked files using Volume Shadow Copy Service. +共有ã€ã¾ãŸã¯ãƒœãƒªãƒ¥ãƒ¼ãƒ シャドウコピーã§ãƒãƒƒã‚¯ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピー Copy to clipboard\tCTRL+C クリップボードã«ã‚³ãƒ”ー\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: ファイルã®ãƒœãƒªãƒ¥ãƒ¼ãƒ åãŒæ±ºå®šã•ã‚Œã¦ã„ã¾ã›ã‚“: Could not initialize directory monitoring: 監視ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’åˆæœŸåŒ–ã§ãã¾ã›ã‚“: +Could not load a required DLL: +å¿…è¦ãªDLLã‚’èªã¿è¾¼ã‚ã¾ã›ã‚“: Could not read values for the following XML nodes: 以下㮠XMLノードã®å€¤ã‚’èªã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥ã¾ã›ã‚“: Create a batch job @@ -298,7 +314,7 @@ Date データ Delay é…延時間 -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds 変更ã®æ¤œå‡ºã¨ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å®Ÿè¡Œé–“ã®é…延(秒) Delete files/folders existing on left side only å·¦å´ã®ã¿ã«å˜åœ¨ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«/フォルダを削除 @@ -386,6 +402,8 @@ Error reading file: ファイルèªã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼: Error reading from synchronization database: åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‹ã‚‰ã®èªã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼: +Error resolving full path name: +フルパスåã®è§£æ±ºã‚¨ãƒ©ãƒ¼: Error resolving symbolic link: シンボリックリンクã®è§£æ±ºã«å¤±æ•—: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files ファイルフィルター Filter has been selected フィルターã¯é¸æŠžæ¸ˆã¿ã§ã™ +Filter settings have changed! +フィルターè¨å®šã¯å¤‰æ›´ã•ã‚Œã¦ã„ã¾ã™! Filter view 表示フィルター Filtering is deactivated @@ -541,7 +561,7 @@ Hints: Homepage ホームページ Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -データベースを使用ã—ã¦ã€ä¸¡å´ã‚¢ã‚¤ãƒ†ãƒ ã®å¤‰æ›´ã‚’特定ã—ã¾ã™ã€‚削除ã€ç«¶åˆã¯è‡ªå‹•çš„ã«æ¤œå‡ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +データベースを使用ã—ã¦ã€ä¸¡å´ã‚¢ã‚¤ãƒ†ãƒ ã®å¤‰æ›´ã‚’特定ã—ã¾ã™ã€‚ 削除ã€ç«¶åˆã¯è‡ªå‹•çš„ã«æ¤œå‡ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ If you like FFS FFS ãŒæ°—ã«å…¥ã£ãŸå ´åˆ Ignore 1-hour file time difference @@ -560,8 +580,8 @@ Include all rows ã™ã¹ã¦ã®è¡Œã‚’å«ã‚ã‚‹ Include temporarily 一時フォルダをå«ã‚ã‚‹ -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -å«ã‚ã‚‹: *.doc;*.zip;*.exe\n除外: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +å«ã‚ã‚‹: *.doc;*.zip;*.exe\n除外: \\stuff\\temp\\* Incompatible synchronization database format: åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ›¸å¼ã«äº’æ›æ€§ãŒã‚ã‚Šã¾ã›ã‚“: Info @@ -572,8 +592,6 @@ Initial synchronization: åŒæœŸå‡¦ç†ã®åˆæœŸåŒ–: Integrate external applications into context menu. The following macros are available: 外部ã®ã‚¢ãƒ—リケーションをコンテã‚ストメニューã«çµ±åˆã€ä»¥ä¸‹ã®ãƒžã‚¯ãƒãŒåˆ©ç”¨ã§ãã¾ã™: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -ゴミ箱をåˆæœŸåŒ–ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã›ã‚“ã§ã—ãŸ!\n\n使用ã—ã¦ã„ã‚‹ OS ãŒã€Windows 以外㮠OS ã§ã™ã€‚\nã“ã®æ©Ÿèƒ½ã‚’使用ã—ãŸã„å ´åˆã¯ã€ä½œè€…ã¾ã§ã”連絡ãã ã•ã„ :) Leave as unresolved conflict 未解決ã®ç«¶åˆã‚’残㙠Left @@ -590,18 +608,22 @@ Log-messages: ãƒã‚°ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: Logging ãƒã‚° +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +WOW64 ã§ã¯ã€ãƒœãƒªãƒ¥ãƒ¼ãƒ シャドウコピーã«å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“ã€FreeFileSync 64-bit 版をãŠè©¦ã—ãã ã•ã„。 Mirror ->> ミラー >> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. å·¦å´ãƒ•ã‚©ãƒ«ãƒ€ã‚’ミラーリングãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—: åŒæœŸå®Œäº†å¾Œã¯ã€å·¦å´ãƒ•ã‚©ãƒ«ãƒ€ã«åˆã‚ã›ã¦å³å´ãƒ•ã‚©ãƒ«ãƒ€ã¯ä¸Šæ›¸ãã•ã‚Œã¾ã™ã€‚ +Monitoring active... +監視を開始ã—ã¾ã™... More than 50% of the total number of files will be copied or deleted! ファイルåˆè¨ˆç·æ•°ã® 50% 以上ãŒå‰Šé™¤ã€ã¾ãŸã¯ã‚³ãƒ”ーã•ã‚Œã¾ã™ Move column down 列を下ã«ç§»å‹• Move column up 列を上ã«ç§»å‹• -Move files to a user-defined directory. -ユーザ定義ディレクトリã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’移動 +Move files into a time-stamped subdirectory. +ファイルをタイムスタンプåã®ã‚µãƒ–フォルダã«ç§»å‹• Moving %x to Recycle Bin %x をゴミ箱ã«ç§»å‹•ä¸ Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y フォルダ %x をユーザ定義ディレクトリ %y ã«ç§»å‹• Multiple... 複数処ç†... +No change since last synchronization! +å‰å›žã®åŒæœŸä»¥é™ã€å¤‰æ›´ã¯ã‚ã‚Šã¾ã›ã‚“! No filter selected フィルターé¸æŠžãªã— Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause 一時åœæ¢ Paused 一時åœæ¢ä¸ -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. - \"Shadow.dll\" (\"Shadow.zip\" アーカイブ内) ã‚’ã€FreeFileSync インストールフォルダã«ã‚³ãƒ”ーã™ã‚‹ã“ã¨ã§ã€ã“ã®æ©Ÿèƒ½ã‚’利用ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚ -Please fill all empty directory fields. -アイテムãŒé¸æŠžã•ã‚Œã¦ã„ã¾ã›ã‚“! Please run a Compare first before synchronizing! åŒæœŸå‡¦ç†ã‚’実行ã™ã‚‹å‰ã«æ¯”較を行ã£ã¦ãã ã•ã„! +Processing folder pair: +フォルダペアを処ç†ä¸: Published under the GNU General Public License: Published under the GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair フォルダペアを除去 Remove local filter settings ãƒãƒ¼ã‚«ãƒ«ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼è¨å®šã‚’除去 +Renaming file %x to %y +ファイル %x ã‚’ %y ã«ãƒªãƒãƒ¼ãƒ ä¸ Report translation error 翻訳エラーã®è©³ç´° Reset @@ -786,6 +810,8 @@ Target directory already existing! 対象ディレクトリã¯ã™ã§ã«å˜åœ¨ã—ã¾ã™! Target file already existing! 対象ファイルã¯æ—¢ã«å˜åœ¨ã—ã¾ã™! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +ã“ã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã¯é€æ¬¡å®Ÿè¡Œã•ã‚Œã¾ã™:\n- ã“れらã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª(サブディレクトリ)内ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯å¤‰æ›´ã•ã‚Œã¦ã„ã¾ã™ã€‚\n- 対応ã™ã‚‹ãƒ‰ãƒ©ã‚¤ãƒ–レターã¯ã€USB 挿入時ã«æœ‰åŠ¹ã«ãªã‚Šã¾ã™ã€‚ The database file is not yet existing, but will be created during synchronization: ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã€ã¾ã å˜åœ¨ã—ã¾ã›ã‚“ãŒã€åŒæœŸå‡¦ç†ã®å®Ÿè¡Œä¸ã«ä½œæˆã•ã‚Œã¾ã™: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! ãƒã‚°ãƒ•ã‚¡ã‚¤ãƒ«ã‚’作æˆå‡ºæ¥ã¾ã›ã‚“! Unable to initialize Recycle Bin! ゴミ箱ã®åˆæœŸåŒ–ãŒå‡ºæ¥ã¾ã›ã‚“! +Unresolved conflicts existing! +未解決ã®ä¸ä¸€è‡´ãŒã‚ã‚Šã¾ã™! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. 未解決ã®ä¸ä¸€è‡´ãŒã‚ã‚Šã¾ã™! \n\nã“ã®ä¸ä¸€è‡´ã‚’無視ã—ã¦åŒæœŸã‚’続行ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚ Update -> æ›´æ–° -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -使用方法: 監視ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’é¸æŠžã—ã¦ã€ã‚³ãƒžãƒ³ãƒ‰ã‚’入力ã—ã¾ã™ã€‚ é¸æŠžã•ã‚ŒãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª(サブディレクトリ)内ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒå¤‰æ›´ã•ã‚Œã‚‹åº¦ã«ã€å…¥åŠ›ã—ãŸã‚³ãƒžãƒ³ãƒ‰ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚ +Usage: +使用方法: Use Recycle Bin ゴミ箱を使用 Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): è¦å‘Š: %x アイテムã®åŒæœŸã«å¤±æ•—ã—ã¾ã—ãŸ: When the comparison is started with this option set the following decision tree is processed: ã“ã®ã‚ªãƒ—ションã§æ¯”較を開始ã—ãŸå ´åˆã¯ã€ä»¥ä¸‹ã®ãƒ„リーã«å¾“ã£ã¦å‡¦ç†ãŒè¡Œã‚ã‚Œã¾ã™: +You can ignore conflicts and continue synchronization. +ã“ã®ä¸ä¸€è‡´ã‚’無視ã—ã¦åŒæœŸã‚’続行ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚ You can ignore the error to consider not existing directories as empty. æ—¢å˜ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒç©ºã§ã¯ãªã„ã¨ã„ã†ã‚¨ãƒ©ãƒ¼ã¯ç„¡è¦–ã§ãã¾ã™ã€‚ You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng index fc554eca..90499bee 100644 --- a/BUILD/Languages/polish.lng +++ b/BUILD/Languages/polish.lng @@ -46,6 +46,8 @@ &Anuluj &Check for new version &Aktualizuj +&Content +&Zawartość &Create batch job &Twórz plik wsadowy &Default @@ -88,6 +90,8 @@ &Tak (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (PamiÄ™taj, że ten problem dotyczy tylko FAT/FAT32!\nW każdym innym przypadku możesz wyÅ‚Ä…czyć opcjÄ™ \"Ignoruj 1-godzinnÄ… różnicÄ™\".) +(Requires an Internet connection!) +(Wymaga poÅ‚Ä…czenia z Internetem!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Porównaj 1. Enter relative file or directory names separated by ';' or a new line. 1. Wprowdź relatywne scieżki do plików lub katalogów oddzielone ';' lub nowÄ… liniÄ…. +1. Select directories to monitor. +1. Wprowadź katalogi do nadzorowania 2. &Synchronize... 2. &Synchronizuj... +2. Enter a command line. +2. Wprowadź komendÄ™. 2. Use wildcard characters '*' and '?'. 2. Użyj wieloznacznika (wildcard) '*' i '?'. 3. Exclude files directly on main grid via context menu. 3. Wyklucz pliki i foldery używajÄ…c prawego przycisku myszki. +3. Press 'Start'. +3. WciÅ›nij 'Start'. <Automatic> <Automatycznie> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Jak wskazuje nazwa, dwa pliki o tej samej nazwie sÄ… równe tylko i wyÅ‚Ä…cznie jeżeli ich zawartość jest jednakowa. Czas modyfikacji nie jest brany pod uwagÄ™. Ta opcja jest raczej użyteczna do sprawdzania spójnoÅ›ci plików niż zadaÅ„ kopii zapasowej.\n\nDrzewko decyzyjne dla tej opcji jest mniejsze: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Twórz plik wsadowy dla automatyzacji procesu. By rozpocząć prace w tym trybie zwyczajnie uruchom plik klikajÄ…c dwa razy lub dodaj go do zadaÅ„ zaplanowanych Twojego systemu. Plik wsadowy może być również przekazywany jako parametr do programu w postaci: FreeFileSync.exe <plikwsadowy>. +At least one directory input field is empty. +Przynajmniej jedno pole jest puste. Auto-adjust columns Autodopasowanie kolumn Automatic mode @@ -192,20 +204,18 @@ Build: Buduj: Cancel Anuluj -Cannot determine sync-direction: Changed filter settings! -Nie można okreÅ›lik kierunku synchronizacji: Zmieniono ustawienia filtra! -Cannot determine sync-direction: No change since last synchronization! -Nie można okreÅ›lik kierunku synchronizacji: Brak zmian od ostatniej synchronizacji! +Cannot determine sync-direction: +Nie można okreÅ›lić kierunku synchronizacji: Category Kategoria Change direction ZmieÅ„ kierunek Comma separated list Lista oddzielona przecinkami -Commandline -Wiersz poleceÅ„ -Commandline is empty! -Wiersz poleceÅ„ jest pusty! +Command line +Linia komend +Command line is empty! +Linia komend jest pusta! Compare Porównaj Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Kopiuj z prawej do lewej Copy from right to left overwriting Kopiuj z prawej do lewej nadpisujÄ…c +Copy locked files +Kopiuj zablokowane pliki Copy new or updated files to right folder. Kopiuj nowe lub aktualniejsze pliki na prawÄ… stronÄ™. +Copy shared or locked files using Volume Shadow Copy Service. +Kopiuj współdzielone lub zablokowane pliki używajÄ…c Volume Shadow Copy Service. Copy to clipboard\tCTRL+C Kopiuj do pamiÄ™ci\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Nie można okreÅ›lić nazwy dysku dla pliku: Could not initialize directory monitoring: Nie można uruchomić monitora katalogów: +Could not load a required DLL: +Nie można zaÅ‚adować wymaganej biblioteki DLL: Could not read values for the following XML nodes: Nie można odczytać wartoÅ›ci dla danych gaÅ‚Ä™zi XML: Create a batch job @@ -298,7 +314,7 @@ Date Data Delay Opóźnienie -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Opóźnienie pomiÄ™dzy wykryciem zmian, a wykonaniem komendy w sekundach Delete files/folders existing on left side only UsuÅ„ pliki/foldery istniejÄ…ce tylko po lewej stronie @@ -386,6 +402,8 @@ Error reading file: BÅ‚Ä…d odczytu pliku: Error reading from synchronization database: BÅ‚Ä…d odczytu z bazy danych synchronizacji: +Error resolving full path name: +BÅ‚ad odczytu peÅ‚nej nazwy dla Å›cieżki: Error resolving symbolic link: BÅ‚Ä…d odczytu dowiÄ…zania symbolicznego: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtruj pliki Filter has been selected Filtr zostaÅ‚ zaznaczony +Filter settings have changed! +Ustawienia filtra ulegÅ‚y zmianie! Filter view Filtr podglÄ…du Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows DoÅ‚Ä…cz wszystkie rzÄ™dy Include temporarily DoÅ‚Ä…cz tymczasowo -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -DoÅ‚Ä…cz: *.doc;*.zip;*.exe\nWyklucz: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +DoÅ‚Ä…cz: *.doc;*.zip;*.exe\nWyklucz: \\stuff\\temp\\* Incompatible synchronization database format: Niepoprawny format bazy danych dla synchronizacji: Info @@ -572,8 +592,6 @@ Initial synchronization: WstÄ™pna synchronizacja: Integrate external applications into context menu. The following macros are available: DoÅ‚Ä…cz zewnÄ™trznÄ… aplikacjÄ™ do menu kontekstowego. DostÄ™pne macra: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Inicjalizacja Kosza nie byÅ‚a możliwa!\n\nPrawdopodobnie nie używasz Windowsa.\nJeżeli chcesz doÅ‚Ä…czyć tÄ… cechÄ™, skontaktuj siÄ™ z autorem. :) Leave as unresolved conflict Zostaw jako nierozwiÄ…zany konflikt Left @@ -590,18 +608,22 @@ Log-messages: Logi: Logging Tworzenie logów +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Tworzenie Shadow Copies dla WOW64 nie jest obsÅ‚ugiwane. Zainstaluj 64 bitowÄ… wersjÄ™ FreeFileSync. Mirror ->> Lustrzana ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Kopia lustrzana lewego folderu: Prawy folder bÄ™dzie nadpisany zawartoÅ›ciÄ… lewego folderu. +Monitoring active... +Monitorowanie aktywne... More than 50% of the total number of files will be copied or deleted! Ponad 50% plików zostanie skopiowanych lub usuniÄ™tych! Move column down PrzesuÅ„ kolumnÄ™ w dół Move column up PrzesuÅ„ kolumnÄ™ do góry -Move files to a user-defined directory. -PrzenieÅ› pliki do katalogu użytkownika. +Move files into a time-stamped subdirectory. +PrzenieÅ› pliki do oznaczonego podkatalogu. Moving %x to Recycle Bin Przenoszenie %x do kosza. Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Przenoszenie folderu %x do katalogu użytkownika %y Multiple... Wiele... +No change since last synchronization! +Brak zmian od ostatniej synchronizacji! No filter selected Nie wybrano żadnego filtra Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pauza Paused Pauza -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Skopiuj odpowiedni plik \"Shadow.dll\" (ulokowany w \"Shadow.zip\") do folderu z instalacjÄ… FreeFileSync aby uaktywnić tÄ… opcjÄ™. -Please fill all empty directory fields. -Podaj foldery do synchronizacji. Please run a Compare first before synchronizing! Przed synchronizacjÄ… należy uruchomić Porównaj! +Processing folder pair: +Przetwarzanie folderów: Published under the GNU General Public License: UdostÄ™pnione na zasadach licencji GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair UsuÅ„ parÄ™ folderów Remove local filter settings UsuÅ„ ustawienia lokalnego filtra +Renaming file %x to %y +Zmiana nazwy pliku %X na %Y Report translation error ZgÅ‚oÅ› bÅ‚Ä…d w tÅ‚umaczeniu Reset @@ -786,6 +810,8 @@ Target directory already existing! Katalog docelowy już istnieje! Target file already existing! Plik docelowy już istnieje! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +Komenda ta jest wykonywana za każdym razem gdy:\n- Pliki w tych katalogach (lub podkatalogach) sÄ… modyfikowane\n- Odpowiednia litera dysku jest aktywna (PodÅ‚Ä…czenie USB) The database file is not yet existing, but will be created during synchronization: Plik bazy danych nie istnieje, ale zostanie utworzony podczas synchronizacji: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Nie można utworzyć pliku z logami! Unable to initialize Recycle Bin! Nie można zainicjalizować Kosz! +Unresolved conflicts existing! +IstniejÄ… nierozwiÄ…zane konflikty! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. IstniejÄ… nierozwiÄ…zane konflikty! \n\nMożesz je zignorować i kontynuÅ‚ować synchronizacjÄ™. Update -> Uaktualnij -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Użycie: Wybierz katalogi do monitorowania i wprowadź komendÄ™. Gdy któryÅ› z plików zostanie zmodyfikowany, w obrÄ™bie katalogów, zostanie uruchomiona podana komenda. +Usage: +Użycie: Use Recycle Bin Użyj kosza Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Uwaga: BÅ‚Ä…d synchronizacji dla \"%x\" elementów: When the comparison is started with this option set the following decision tree is processed: Gdy porównywanie z zaznaczonÄ… opcjÄ… jest w toku, podejmowane sÄ… nastÄ™pujÄ…ce dezyje: +You can ignore conflicts and continue synchronization. +Możesz je zignorować i kontynuÅ‚ować synchronizacjÄ™. You can ignore the error to consider not existing directories as empty. Możesz zignorować ten bÅ‚Ä…d i uznać nieistniejÄ…cy katalog za pusty. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng index 83518934..09acd77e 100644 --- a/BUILD/Languages/portuguese.lng +++ b/BUILD/Languages/portuguese.lng @@ -46,6 +46,8 @@ &Cancelar &Check for new version &Procurar actualizações +&Content + &Create batch job &Criar um ficheiro batch &Default @@ -88,6 +90,8 @@ &Sim (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Apenas as drives FAT/FAT32 são afectadas por este problema! \nPara todas as outras situações pode desactivar a opção \"ignorar diferença de 1 hora\".) +(Requires an Internet connection!) + , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Comparar 1. Enter relative file or directory names separated by ';' or a new line. 1. Inserir caminho(s) do(s) ficheiro(s) ou pasta(s) separados por ';' ou numa nova linha. +1. Select directories to monitor. + 2. &Synchronize... 2. &Sincronizar... +2. Enter a command line. + 2. Use wildcard characters '*' and '?'. 2. Usar '*' e '?' como caracteres de procura. 3. Exclude files directly on main grid via context menu. 3. Excluir ficheiros directamente da grelha através do menu de contexto. +3. Press 'Start'. + <Automatic> <Automático> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Como o nome sugere, dois ficheiros com o mesmo nome são assinalados iguais se e só se o seu conteúdo for idêntico. Esta opção é útil para controles de consistência mais do que para efeitos de backup. Portanto, a data dos ficheiros não é tomada em conta.\n\nCom esta opção, a arvoré de decisão é menor: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Criar um batch para sincronização automática. Para iniciar o modo batch, passar o nome do ficheiro para o executável do FreeFileSync: FreeFileSync.exe <ficheiro batch>. Também pode ser calendarizado no programador de tarefas. +At least one directory input field is empty. + Auto-adjust columns Auto ajustar colunas Automatic mode @@ -192,20 +204,18 @@ Build: Criado: Cancel Cancelar -Cannot determine sync-direction: Changed filter settings! -Não é possÃvel determinar a direcção de sincronização: Alterações na configuração do filtro! -Cannot determine sync-direction: No change since last synchronization! -Não é possÃvel determinar a direcção de sincronização: Não há alterações desde a última sincronização! +Cannot determine sync-direction: + Category Categoria Change direction Mudar direcção Comma separated list Lista de itens separados por virgula -Commandline +Command line Linha de comandos -Commandline is empty! -Linha de comandos vazia! +Command line is empty! + Compare Comparar Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Copiar da direita para a esquerda Copy from right to left overwriting Copiar da direita para a esquerda com sobreposição +Copy locked files + Copy new or updated files to right folder. Copiar ficheiros novos ou actualizados para a direita +Copy shared or locked files using Volume Shadow Copy Service. + Copy to clipboard\tCTRL+C Copiar para a Ãrea de transferência\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Não é possÃvel determinar o nome do volume para o ficheiro: Could not initialize directory monitoring: Não é possÃvel iniciar monitorização do directório: +Could not load a required DLL: + Could not read values for the following XML nodes: Não foi possÃvel ler os valores dos seguintes nós XML: Create a batch job @@ -298,7 +314,7 @@ Date Data Delay Atraso -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Atraso entre a detecção de diferenças e a execuçao dos comandos em segundos Delete files/folders existing on left side only Eliminar itens existentes apenas no lado esquerdo @@ -386,6 +402,8 @@ Error reading file: Erro de leitura de ficheiro: Error reading from synchronization database: Erro ao ler a base de dados de sincronização: +Error resolving full path name: + Error resolving symbolic link: Erro na resolução do link simbólico: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtrar ficheiros Filter has been selected +Filter settings have changed! + Filter view Filtrar vista Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Include temporarily Incluir temporariamente -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Incluir: *.doc;*.zip;*.exe\nExcluir: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Incluir: *.doc;*.zip;*.exe\nExcluir: \\stuff\\temp\\* Incompatible synchronization database format: Formato de base de dados de sincronização incompatÃvel: Info @@ -572,8 +592,6 @@ Initial synchronization: Sincronização inicial: Integrate external applications into context menu. The following macros are available: Integrar aplicações externas no menu de contexto. As seguintes macros estão disponÃveis: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Não é possÃvel aceder à Reciclagem!\n\nÉ possÃvel que não esteja a utilizar Windows.\nSe desejar esta opção incluÃda, é favor contactar o autor. :) Leave as unresolved conflict Deixar como conflito Left @@ -590,18 +608,22 @@ Log-messages: Log de mensagens: Logging A escrever em log +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. + Mirror ->> Espelhar ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Espelhar pasta da esquerda: A pasta da direita vai ser sobreposta e uma cópia exacta da pasta esquerda após sincronização. +Monitoring active... + More than 50% of the total number of files will be copied or deleted! Mais de 50% dos ficheiros vai ser copiado ou apagado! Move column down Mover coluna para baixo Move column up Mover coluna para cima -Move files to a user-defined directory. -Mover ficheiros para um directório definido pelo utilizador. +Move files into a time-stamped subdirectory. + Moving %x to Recycle Bin A mover %x para a Reciclagem Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y A mover pasta %x para o directório %y Multiple... Multiplo... +No change since last synchronization! + No filter selected Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pausa Paused Em pausa -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Por favor copie o \"Shadow.dll\" correcto (localizado no arquivo \"Shadow.zip\") para a pasta da instalação do FreeFileSync para activar esta opção. -Please fill all empty directory fields. -Por favor, preencha todos os campos vazios. Please run a Compare first before synchronizing! +Processing folder pair: + Published under the GNU General Public License: Publicado sobre GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair Remover o par de pastas Remove local filter settings +Renaming file %x to %y + Report translation error Informar um erro de tradução Reset @@ -786,6 +810,8 @@ Target directory already existing! Directório de destino já existe! Target file already existing! Ficheiro de destino já existe! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) + The database file is not yet existing, but will be created during synchronization: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Não é possÃvel criar ficheiro log! Unable to initialize Recycle Bin! Não é possÃvel iniciar a Reciclagem! +Unresolved conflicts existing! + Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Existem conflitos não resolvidos! \n\nPode ignorá-los e continuar a sincronização. Update -> Actualizar -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Uso: Selecionar directórios a monitorizar e escrever uma linha de comando. Cada vez que um ficheiro for alterado nestes directórios (ou subdirectórios) a linha de comando será executada. +Usage: + Use Recycle Bin Utilizar Reciclagem Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Atenção: A sincronização falhou para %x item(s): When the comparison is started with this option set the following decision tree is processed: Usar a seguinte árvore de decisão quando inicia com estas opções de comparação: +You can ignore conflicts and continue synchronization. + You can ignore the error to consider not existing directories as empty. Pode ignorar o erro para considerar directórios não existentes como vazios. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng index 081e1b96..7783f823 100644 --- a/BUILD/Languages/portuguese_br.lng +++ b/BUILD/Languages/portuguese_br.lng @@ -46,6 +46,8 @@ &Cancelar &Check for new version &Procurar novas versões +&Content +Conteúdo &Create batch job &Criar um arquivo batch &Default @@ -88,6 +90,8 @@ &Sim (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Note que apenas discos FAT/FAT32 são afetados por este problema!\nEm todos os outros casos pode-se desabilitar esta opção \"ignorar diferença de 1 hora\".) +(Requires an Internet connection!) +(Requer conexão com a Internet!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Comparar 1. Enter relative file or directory names separated by ';' or a new line. 1. Entre os nomes dos arquivos ou diretórios relativos separados por ';' ou uma nova linha. +1. Select directories to monitor. +1. Selecione os diretórios para monitorar. 2. &Synchronize... 2. &Sincronizar... +2. Enter a command line. +2. Entre uma linha de comando. 2. Use wildcard characters '*' and '?'. 2. Usar '*' e '?' como caracteres coringa. 3. Exclude files directly on main grid via context menu. 3. Excluir arquivos diretamente do grid principal através do menu de contexto. +3. Press 'Start'. +3. Pressione 'Iniciar'. <Automatic> <Automático> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Como o nome sugere, dois arquivos com o mesmo nome são assinalados como iguais se e somente se eles tiverem o mesmo conteúdo. Esta opção é útil para controles de consistência mais do que para efeitos de backup. Portanto, a data dos arquivos não é levada em consideração.\n\nCom esta opção, a árvore de decisão é menor: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Monta um arquivo batch para sincronização automatizada. Para iniciar o modo batch, passar o nome do arquivo para o executável do FreeFileSync: FreeFileSync.exe <arquivo batch>. Também pode ser programado no Agendador de Tarefas do sistema operacional. +At least one directory input field is empty. +Pelo menos um dos campos de entrada de diretório está vazio. Auto-adjust columns Autoajustar colunas Automatic mode @@ -192,20 +204,18 @@ Build: Criado: Cancel Cancelar -Cannot determine sync-direction: Changed filter settings! -Não foi possÃvel determinar a direção de sicronização: Configurações do filtro alteradas! -Cannot determine sync-direction: No change since last synchronization! -Não foi possÃvel determinar a direção de sicronização: Nenhuma alteração desde a última sincronização! +Cannot determine sync-direction: +Não foi possÃvel determinar a direção de sincronização: Category Categoria Change direction Inverter sentido Comma separated list Lista de itens separada por vÃrgula -Commandline +Command line Linha de comando -Commandline is empty! -A linha de comando está vazia! +Command line is empty! +Linha de comando está vazia! Compare Comparar Compare both sides @@ -260,8 +270,12 @@ Copy from right to left Copiar da direita para a esquerda Copy from right to left overwriting Copiar da direita para a esquerda com sobreposição +Copy locked files +Copiar arquivos bloqueados (em uso) Copy new or updated files to right folder. Copiar arquivos novos ou atualizados para a pasta da direita +Copy shared or locked files using Volume Shadow Copy Service. +Copiar arquivos compartilhados ou bloqueados usando o Serviço de Cópias de Sombra de Volume. Copy to clipboard\tCTRL+C Copiar para a Ãrea de transferência\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Não foi possÃvel determinar o nome do volume para o arquivo: Could not initialize directory monitoring: Não foi possÃvel inicializar o monitoramento de diretórios: +Could not load a required DLL: +Não foi possÃvel carregar uma DLL requerida: Could not read values for the following XML nodes: Não foi possÃvel ler os valores para os seguintes nós XML: Create a batch job @@ -298,7 +314,7 @@ Date Data Delay Atraso -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Atraso entre detecção de mudanças e execução de linha de comando em segundos Delete files/folders existing on left side only Apagar arquivos/pastas existentes apenas no lado esquerdo @@ -386,6 +402,8 @@ Error reading file: Erro ao ler arquivo: Error reading from synchronization database: Erro ao ler do banco de dados de sincronização: +Error resolving full path name: +Erro na resolução do caminho completo: Error resolving symbolic link: Erro na resolução de link simbólico: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtrar arquivos Filter has been selected Filtro foi selecionado +Filter settings have changed! +As configurações do filtro foram alteradas! Filter view Filtrar vista Filtering is deactivated @@ -541,11 +561,11 @@ Dicas: Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identificar e propagar mudanças em ambos os lados usando o banco de dados. Exclusões e conflitos serão detectados automaticamente. +Identificar e propagar mudanças em ambos os lados utilizando um banco de dados. Exclusões e conflitos serão detectados automaticamente. If you like FFS Se gosta do FFS Ignore 1-hour file time difference -Ignorar diferença de tempo de 1 hora +Ignorar diferenças de 1 hora nos arquivos Ignore errors Ignorar erros Ignore subsequent errors @@ -560,8 +580,8 @@ Include all rows Incluir todas as linhas Include temporarily Incluir temporariamente -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Incluir: *.doc;*.zip;*.exe\nExcluir: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Incluir: *.doc;*.zip;*.exe\nExcluir: \\stuff\\temp\\* Incompatible synchronization database format: Formato de banco de dados de sincronização incompatÃvel: Info @@ -572,8 +592,6 @@ Initial synchronization: Sincronização inicial: Integrate external applications into context menu. The following macros are available: Integrar aplicações externas no menu de contexto. As seguintes macros estão disponÃveis: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Não foi possÃvel acessar a Lixeira!\n\nÉ possÃvel que não esteja utilizando Windows.\nSe desejar esta opção incluÃda, favor contatar o autor. :) Leave as unresolved conflict Deixar como conflito não resolvido Left @@ -590,18 +608,22 @@ Log-messages: Log de mensagens: Logging Gravando log +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Cópias de sombra no WOW64 não são suportadas. Por favor use a versão 64-bits do FreeFileSync. Mirror ->> Espelhar ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Espelhar pasta da esquerda: A pasta da direita vai ser sobreposta e será feita uma cópia exata da pasta da esquerda após a sincronização. +Monitoring active... +Monitoramento ativo... More than 50% of the total number of files will be copied or deleted! Mais de 50% do número total de arquivos será copiado ou apagado! Move column down Mover coluna para baixo Move column up Mover coluna para cima -Move files to a user-defined directory. -Mover arquivos para um diretório especificado. +Move files into a time-stamped subdirectory. +Mover arquivos para um subdiretório com carimbo de tempo. Moving %x to Recycle Bin Movendo %x para a Lixeira Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Movendo pasta %x para o diretório especificado Multiple... Múltiplos... +No change since last synchronization! +Nenhuma mudança desde a última sincronização! No filter selected Nenhum filtro selecionado Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pausa Paused Pausado -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Por favor, copie o \"Shadow.dll\" apropriado (localizado no arquivo \"Shadow.zip\") no diretório de instalação do FreeFileSync para habilitar essa funcionalidade. -Please fill all empty directory fields. -Por favor, preencha todos os campos de diretórios vazios. Please run a Compare first before synchronizing! Por favor execute primeiro a Comparação antes de sincronizar! +Processing folder pair: +Processando par de pastas: Published under the GNU General Public License: Publicado sobre a GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair Remover par de pastas Remove local filter settings Remover configurações locais de filtro +Renaming file %x to %y +Renomeando arquivo %x para %y Report translation error Reportar erro de tradução Reset @@ -786,6 +810,8 @@ Target directory already existing! Diretório de destino já existe! Target file already existing! Arquivo de destino já existe! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +A linha de comando é executada cada vez que:\n- Arquivos dentro desses diretórios (ou subdiretórios) são modificados\n- A letra correspondente do disco se torna disponÃvel (inserção de USB) The database file is not yet existing, but will be created during synchronization: O arquivo de banco de dados ainda não existe, mas será criado durante a sincronização: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Não foi possÃvel criar arquivo log! Unable to initialize Recycle Bin! Não foi possÃvel abrir a Lixeira! +Unresolved conflicts existing! +Conflitos não resolvidos existentes! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Conflitos não resolvidos existentes! \n\nVocê pode ignorar os conflitos e continuar a sincronização. Update -> Atualizar -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Uso: Selecionar diretórios para monitoração e entrar com linha de comando. Cada vez que os arquivos são modificados nesses diretórios (ou subdiretórios) a linha de comando é executada. +Usage: +Uso: Use Recycle Bin Utilizar Lixeira Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Atenção: A sincronização falhou para %x item(s): When the comparison is started with this option set the following decision tree is processed: Quando a comparação é iniciada com esta opção, a seguinte árvore de decisão é processada: +You can ignore conflicts and continue synchronization. +Você pode ignorar os conflitos e continuar a sincronização. You can ignore the error to consider not existing directories as empty. Você pode ignorar o erro para considerar diretórios não existente como vazios. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng index 8bdf1247..52f715a6 100644 --- a/BUILD/Languages/romanian.lng +++ b/BUILD/Languages/romanian.lng @@ -46,6 +46,8 @@ &Anulează &Check for new version &Caută Versiune Nouă +&Content +&ConÈ›inut &Create batch job &Creează o Sarcină Lot &Default @@ -88,12 +90,14 @@ &Da (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Doar dispozitivele FAT/FAT32 sînt afectate de această problemă!\nÃŽn celelalte cazuri, puteÈ›i dezactiva setarea \"ignoră diferenÈ›a de 1-oră\".) +(Requires an Internet connection!) +(Necesită o conexiune la internet!) , . - Other side's counterpart to %dir -- Corespondentul din partea opusă al lui %dir +- corespondentul din partea opusă al lui %dir - Other side's counterpart to %name -- Corespondentul din partea opusă al lui %name +- corespondentul din partea opusă al lui %name - conflict - conflict - conflict (same date, different size) @@ -132,12 +136,18 @@ 1. &Compară 1. Enter relative file or directory names separated by ';' or a new line. 1. IntroduceÈ›i numele relative ale fiÈ™ierelor sau dosarelor, separate de semnul ';' sau de un rînd nou. +1. Select directories to monitor. +1. SelectaÈ›i dosarele de monitorizat. 2. &Synchronize... 2. &Sincronizează... +2. Enter a command line. +2. IntroduceÈ›i calea. 2. Use wildcard characters '*' and '?'. 2. FolosiÈ›i metacaracterele '*' È™i '?' (asterisc È™i semn de întrebare). 3. Exclude files directly on main grid via context menu. 3. ExcludeÈ›i fiÈ™ierele È™i dosarele direct de pe grila principală cu ajutorul meniului contextual. +3. Press 'Start'. +3. ApăsaÈ›i 'Start'. <Automatic> <Sincronizare Inteligentă> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if AÈ™a cum sugerează È™i numele, două fiÈ™iere cu acelaÈ™i nume sînt considerate identice dacă È™i numai dacă este identic È™i conÈ›inutul lor. Această opÈ›iune este utilă mai degrabă pentru verificările de consecvență decît pentru operaÈ›iunile de salvgardare [backup]. AÈ™a că timpurile fiÈ™ierelor (data È™i ora) nu sînt luaÈ›i deloc în considerare.\n\nCu această opÈ›iune activată, arborele de decizie e mai simplu: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Se poate crea un fiÈ™ier cu un lot de comenzi [batch file] pentru sincronizarea inteligentă. Pentru a porni în modul lot, indicaÈ›i astfel numele fiÈ™ierului lot pentru prelucrarea sa de către executabilul FreeFileSync: freefilesync.exe <fiÈ™ier lot>. Această operaÈ›iune poate fi programată în planificatorul de sarcini al sistemului de operare [task scheduler]. +At least one directory input field is empty. +Cel puÈ›in un cîmp de introducere a dosarului este gol. Auto-adjust columns Autoajustează Coloanele Automatic mode @@ -192,19 +204,17 @@ Build: Compilat la: Cancel Anulează -Cannot determine sync-direction: Changed filter settings! -Nu se poate determina sensul de sincronizare: Setările filtrului s-au schimbat! -Cannot determine sync-direction: No change since last synchronization! -Nu se poate determina sensul de sincronizare: Nici o modificare de la ultima sincronizare! +Cannot determine sync-direction: +Nu se poate determina sensul de sincronizare: Category Categorie Change direction Schimbă în Sensul IconiÈ›ei Comma separated list Listă de elemente separate prin virgulă -Commandline +Command line Linie de comandă -Commandline is empty! +Command line is empty! Linia de comandă este goală! Compare Compară @@ -260,8 +270,12 @@ Copy from right to left Copiază de la Dreapta la Stînga Copy from right to left overwriting Copiază de la Dreapta la Stînga cu Suprascriere +Copy locked files +Copiază fiÈ™ierele zăvorîte [locked] Copy new or updated files to right folder. Copiere în dosarul din dreapta a fiÈ™ierelor actualizate sau noi. +Copy shared or locked files using Volume Shadow Copy Service. +Copiază fiÈ™ierele partajate sau zăvorîte folosind serviciul de salvgardare din Windows. Copy to clipboard\tCTRL+C Copiază în CliplanÈ™etă\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Nu pot determina numele volumului pentru fiÈ™ierul: Could not initialize directory monitoring: Nu pot iniÈ›ializa monitorizarea dosarelor: +Could not load a required DLL: +Nu pot încărca un fiÈ™ier DLL necesar: Could not read values for the following XML nodes: Nu pot citi valorile pentru următoarele noduri XML: Create a batch job @@ -298,7 +314,7 @@ Date Dată Delay ÃŽntîrziere -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds ÃŽntîrziere în secunde între detectarea modificărilor È™i executarea liniei de comandă Delete files/folders existing on left side only Șterge Itemul din Stînga @@ -386,6 +402,8 @@ Error reading file: Eroare la citirea fiÈ™ierului: Error reading from synchronization database: Eroare la citirea din baza de date a sincronizării: +Error resolving full path name: +Eroare la rezolvarea numelui căii complete: Error resolving symbolic link: Eroare la rezolvarea legăturii simbolice: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtrează FiÈ™ierele Filter has been selected Filtrul a fost selectat +Filter settings have changed! +Setările filtrului au fost schimbate! Filter view Filtru de Vedere Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Include Toate Rîndurile Include temporarily Include Temporar -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Incluse: *.doc;*.zip;*.exe\nExcluse: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Incluse: *.doc;*.zip;*.exe\nExcluse: \\stuff\\temp\\* Incompatible synchronization database format: Format incompatibil al bazei de date a sincronizării: Info @@ -572,8 +592,6 @@ Initial synchronization: Sincronizare iniÈ›ială: Integrate external applications into context menu. The following macros are available: Include aplicaÈ›iile externe în meniul contextual. Sînt disponibile următoarele macrocomenzi: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -IniÈ›ializarea Reciclatorului nu a fost posibilă!\n\nCauza poate fi faptul că nu utilizaÈ›i SO Windows.\nDacă doriÈ›i să utilizaÈ›i această funcÈ›ionalitate, contactaÈ›i autorul. :) Leave as unresolved conflict Lasă ca Conflict Nerezolvat Left @@ -590,18 +608,22 @@ Log-messages: Mesaje de jurnalizare: Logging Jurnalizez +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Realizarea de copii de rezervă prin sistemul WOW64 nu este suportată. FolosiÈ›i versiunea pe 64-biÈ›i a FreeFileSync. Mirror ->> Clonare =>> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Salvgardare [backup] prin clonare a dosarului stîng: dosarul din dreapta va fi suprascris È™i va fi identic după sincronizare cu dosarul din stînga. +Monitoring active... +Monitorizare activă... More than 50% of the total number of files will be copied or deleted! Peste 50% din numărul total de fiÈ™iere vor fi copiate sau distruse! Move column down Mută coloana în jos Move column up Mută coloana în sus -Move files to a user-defined directory. -FiÈ™ierele sînt mutate într-un dosar ales de utilizator. +Move files into a time-stamped subdirectory. +Mută fiÈ™ierele într-un subdosar cu marcaj de timp. Moving %x to Recycle Bin Mut %x în Reciclator Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Mut dosarul %x în dosarul %y ales de utilizator Multiple... Multiplu... +No change since last synchronization! +Nu sînt schimbări de la ultima sincronizare! No filter selected Nu a fost selectat nici un filtru Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Pauză Paused Pauzat -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -CopiaÈ›i fiÈ™ierul \"Shadow.dll\" (din arhiva \"Shadow.zip\") în dosarul de instalare FreeFileSync pentru a putea utiliza această funcÈ›ionalitate. -Please fill all empty directory fields. -CompletaÈ›i toate cîmpurile unde trebuie să apară adrese ale dosarelor comparate. Please run a Compare first before synchronizing! RulaÈ›i compararea înainte de a sincroniza! +Processing folder pair: +Procesez perechea de dosare: Published under the GNU General Public License: Publicat sub licenÈ›a GNU GPL: Question @@ -670,6 +692,8 @@ Remove folder pair ÃŽnlătură Perechea de Dosare Remove local filter settings ÃŽnlătură ConfiguraÈ›ia Filtrului Local +Renaming file %x to %y +Redenumesc fiÈ™ierul %x în %y Report translation error Raportarea erorilor de traducere Reset @@ -786,6 +810,8 @@ Target directory already existing! Dosarul È›intă există deja! Target file already existing! FiÈ™ierul È›intă există deja! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +Linia de comandă este executată de fiecare dată:\n- FiÈ™ierele din aceste dosare (sau subdosare) sînt modificate\n- Litera corespunzătoare a dispozitivului devine disponibilă (introducere-USB) The database file is not yet existing, but will be created during synchronization: FiÈ™ierul cu baza de date nu există încă, dar va fi creat în cursul sincronizării: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! FiÈ™ierul jurnal nu poate fi creat! Unable to initialize Recycle Bin! Reciclatorul nu poate fi iniÈ›ializat! +Unresolved conflicts existing! +Există conflicte nerezolvate! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Există conflicte nerezolvate!\n\nPuteÈ›i ignora conflictele pentru a continua cu sincronizarea. Update -> Actualizare => -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Utilizare: SelectaÈ›i dosarele de sincronizat È™i introduceÈ›i o linie de comandă. De fiecare dată cînd un fiÈ™ier este modificat în aceste dosare (sau subdosare), este executată linia de comandă. +Usage: +Utilizare: Use Recycle Bin Mută în reciclator Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): AtenÈ›ie: Sincronizarea a eÈ™uat pentru %x itemuri: When the comparison is started with this option set the following decision tree is processed: Cînd compararea este pornită cu acest set de opÈ›iuni, este executat următorul arbore de decizie: +You can ignore conflicts and continue synchronization. +PuteÈ›i ignora conflictele pentru a continua cu sincronizarea. You can ignore the error to consider not existing directories as empty. PuteÈ›i ignora eroarea care consideră că un dosar inexistent este gol. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng index f2dd49ef..fc461c2e 100644 --- a/BUILD/Languages/russian.lng +++ b/BUILD/Languages/russian.lng @@ -46,6 +46,8 @@ &Отмена &Check for new version &Проверить наличие новой верÑии +&Content +&Справка &Create batch job &Создать задание... &Default @@ -88,6 +90,8 @@ &Да (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Помните, что только диÑки FAT/FAT32 Ñтрадают от Ñтой проблемы!\nВо вÑех оÑтальных ÑлучаÑÑ… вы можете отключить параметр \"игнорировать 1-чаÑовую разницу\".) +(Requires an Internet connection!) +(ТребуетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ к Интернету!) , . - Other side's counterpart to %dir @@ -132,12 +136,18 @@ 1. &Сравнить 1. Enter relative file or directory names separated by ';' or a new line. 1. Введите имена файлов или папок, разделÑÑ Ð·Ð½Ð°ÐºÐ¾Ð¼ ';' или Ñ Ð½Ð¾Ð²Ð¾Ð¹ Ñтроки. +1. Select directories to monitor. +1. Выберите папки Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð°; 2. &Synchronize... 2. &Синхронизировать +2. Enter a command line. +2. Введите командную Ñтроку; 2. Use wildcard characters '*' and '?'. 2. ИÑпользуйте Ñимволы '*' и '?' Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ‹ неизвеÑтных. 3. Exclude files directly on main grid via context menu. 3. ИÑключите файлы прÑмо в главном окне через контекÑтное меню. +3. Press 'Start'. +3. Ðажмите 'Старт'. <Automatic> <ÐвтоматичеÑкий> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Как напиÑано в названии, два файла Ñ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ñ‹Ð¼ именем отмечаютÑÑ Ñ€Ð°Ð²Ð½Ñ‹Ð¼Ð¸, только еÑли они имеют то же Ñамое Ñодержание. Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð° Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ ÑоглаÑованноÑти, а не операции резервного копированиÑ. ПоÑтому даты файлов не учитываютÑÑ Ð²Ð¾Ð¾Ð±Ñ‰Ðµ.\n\nС Ñтой опцией алгоритм короче: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Создайте файл Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ð·Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð¾Ð¹ Ñинхронизации. Чтобы запуÑтить программу в Ñтом режиме проÑто передайте название файла на выполнение FreeFileSync: FreeFileSync.exe <batchfile>. Ðто также может быть запиÑано в планировщике задач Вашей операционной ÑиÑтемы. +At least one directory input field is empty. +По крайней мере, одно поле путей папок не заполнено. Auto-adjust columns Ðвтовыравнивание ширины колонок Automatic mode @@ -192,19 +204,17 @@ Build: Сборка: Cancel Отмена -Cannot determine sync-direction: Changed filter settings! -Ðевозможно определить направление Ñинхронизации: Изменены наÑтройки фильтра! -Cannot determine sync-direction: No change since last synchronization! -Ðевозможно определить направление Ñинхронизации: Ðикаких изменений поÑле поÑледней Ñинхронизации! +Cannot determine sync-direction: +Ðевозможно определить направление Ñинхронизации: Category ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Change direction ПоменÑÑ‚ÑŒ направление Comma separated list СпиÑок, разделÑемый запÑтыми -Commandline +Command line ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока -Commandline is empty! +Command line is empty! ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока пуÑта! Compare Сравнить @@ -260,8 +270,12 @@ Copy from right to left Скопировать Ñправа налево Copy from right to left overwriting Скопировать Ñправа налево Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñью +Copy locked files +Копировать заблокированные файлы Copy new or updated files to right folder. Копировать новые или обновлÑÑ‚ÑŒ файлы на правой Ñтороне. +Copy shared or locked files using Volume Shadow Copy Service. +Копировать общие или заблокированные файлы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Службы Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°. Copy to clipboard\tCTRL+C Копировать в буфер обмена\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Ðе удалоÑÑŒ определить название тома Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð°: Could not initialize directory monitoring: Ðе удалоÑÑŒ инициализировать папку Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð°: +Could not load a required DLL: +Ðе удалоÑÑŒ загрузить необходимые DLL: Could not read values for the following XML nodes: Ðе удалоÑÑŒ прочитать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñледующих XML запиÑей: Create a batch job @@ -298,7 +314,7 @@ Date Дата Delay Задержка -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Задержка между обнаружением изменений и выполнением командной Ñтроки в Ñекундах Delete files/folders existing on left side only УдалÑÑ‚ÑŒ файлы/папки, ÑущеÑтвующие только на левой Ñтороне @@ -386,6 +402,8 @@ Error reading file: Ошибка при чтении файла: Error reading from synchronization database: Ошибка при чтении из базы данных Ñинхронизации: +Error resolving full path name: +Ошибка при воÑÑтановлении абÑолютного пути из отноÑительного: Error resolving symbolic link: Ошибка при решении ÑимволичеÑкой ÑÑылки: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Фильтр файлов Filter has been selected Фильтр уÑтановлен +Filter settings have changed! +ÐаÑтройки фильтра были изменены! Filter view Вид фильтра Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð²Ñе Ñтроки Include temporarily Ð’ÐºÐ»ÑŽÑ‡Ð°Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ñ‹Ðµ -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -ВключаÑ: *.doc;*.zip;*.exe\nИÑключаÑ: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +ВключаÑ: *.doc;*.zip;*.exe\nИÑключаÑ: \\stuff\\temp\\* Incompatible synchronization database format: ÐеÑовмеÑтимый формат базы данных Ñинхронизации: Info @@ -572,8 +592,6 @@ Initial synchronization: ÐŸÐµÑ€Ð²Ð¾Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ ÑинхронизациÑ: Integrate external applications into context menu. The following macros are available: Интегрирует внешние Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² контекÑтное меню.\nСледующие команды доÑтупны: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Ðевозможно инициализировать "Корзину"!\n\nВероÑтно, что Ð’Ñ‹ не иÑпользуете Windows.\nЕÑли Ð’Ñ‹ хотите, чтобы Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð±Ñ‹Ð»Ð°, пожалуйÑта ÑвÑжитеÑÑŒ Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð¾Ð¼. :) Leave as unresolved conflict ОÑтавить как нерешенный конфликт Left @@ -590,18 +608,22 @@ Log-messages: Лог-ÑообщениÑ: Logging Лог-файлы +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Создание теневых копий на WOW64 не поддерживаетÑÑ. ПожалуйÑта, иÑпользуйте FreeFileSync 64-разрÑдной верÑии. Mirror ->> Зеркало ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Ð ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð»ÐµÐ²Ð¾Ð¹ папки: Ð¿Ñ€Ð°Ð²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° будет перезапиÑана и поÑле Ñинхронизации будет точно ÑоответÑтвовать левой папке. +Monitoring active... +Мониторинг включен... More than 50% of the total number of files will be copied or deleted! Более 50% общего количеÑтва файлов будет Ñкопировано или удалено! Move column down ПеремеÑтить вниз Move column up ПеремеÑтить вверх -Move files to a user-defined directory. -ПеремеÑтить файлы в заданную пользователем папку +Move files into a time-stamped subdirectory. +ПеремеÑтить файлы во временно-отмеченную подпапку. Moving %x to Recycle Bin Отправка %x в "Корзину" Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Перемещение папки %x в заданную пользователем папку %y Multiple... Различные варианты Ñинхронизации +No change since last synchronization! +Ðикаких изменений Ñ Ð¿Ð¾Ñледней Ñинхронизации! No filter selected Ðи один фильтр не выбран Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Пауза Paused Пауза -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -ПожалуйÑта, Ñкопируйте ÑоответÑтвующий \"Shadow.dll\" (находÑщийÑÑ Ð² архиве \"Shadow.zip\") в папку уÑтановки FreeFileSync Ð´Ð»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñтой функции. -Please fill all empty directory fields. -ПожалуйÑта, заполните вÑе пуÑтые Ð¿Ð¾Ð»Ñ Ð¿Ð°Ð¿Ð¾Ðº Please run a Compare first before synchronizing! ПожалуйÑта, запуÑтите Ñравнение перед Ñинхронизацией! +Processing folder pair: +Обработка пары папок: Published under the GNU General Public License: ИздаетÑÑ Ð¿Ð¾Ð´ GNU General Public License: Question @@ -670,6 +692,8 @@ Remove folder pair Удалить пару папок Remove local filter settings Удалить наÑтройки локального фильтра +Renaming file %x to %y +Переименование файла %x в %y Report translation error Сообщить об ошибке перевода Reset @@ -786,6 +810,8 @@ Target directory already existing! ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° уже ÑущеÑтвует! Target file already existing! Конечный файл уже ÑущеÑтвует! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока выполнÑетÑÑ ÐºÐ¾Ð³Ð´Ð°:\n- Файлы в Ñтих папках (или подпапках) были изменены\n- СоответÑÑ‚Ð²ÑƒÑŽÑ‰Ð°Ñ Ð±ÑƒÐºÐ²Ð° диÑка ÑтановитÑÑ Ð´Ð¾Ñтупной (добавление USB уÑтройÑтва) The database file is not yet existing, but will be created during synchronization: Файл базы данных еще не ÑущеÑтвует, но будет Ñоздан во Ð²Ñ€ÐµÐ¼Ñ Ñинхронизации: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Ðевозможно Ñоздать лог! Unable to initialize Recycle Bin! Ðевозможно инициализировать "Корзину"! +Unresolved conflicts existing! +СущеÑтвуют нерешенные конфликты Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. -СущеÑтвуют нерешенные конфликты \n\nÐ’Ñ‹ можете проигнорировать их и продолжить Ñинхронизацию. +СущеÑтвуют нерешенные конфликты! \n\nÐ’Ñ‹ можете проигнорировать их и продолжить Ñинхронизацию. Update -> Обновить -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Выберите папки Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ð° и введите командную Ñтроку. Каждый раз при обновлении Ñтих папок (или их подпапок) ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока будет выполнÑÑ‚ÑŒÑÑ. +Usage: +ИнÑтрукциÑ: Use Recycle Bin ИÑпользовать "Корзину" Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Внимание: Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ð²Ð°Ð»ÐµÐ½Ð° Ð´Ð»Ñ %x When the comparison is started with this option set the following decision tree is processed: Когда Ñравнение запущено Ñ Ñтими критериÑми, алгоритм Ñледующий: +You can ignore conflicts and continue synchronization. +Ð’Ñ‹ можете проигнорировать их и продолжить Ñинхронизацию. You can ignore the error to consider not existing directories as empty. Ð’Ñ‹ можете проигнорировать ошибку, принÑв неÑущеÑтвующие папки за пуÑтые. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng index 1dab4ba0..59daefa7 100644 --- a/BUILD/Languages/slovenian.lng +++ b/BUILD/Languages/slovenian.lng @@ -46,6 +46,8 @@ &PrekliÄi &Check for new version &Preveri za novo razliÄico +&Content +&Vsebina &Create batch job &Ustvari batch opravilo &Default @@ -75,7 +77,7 @@ Na&loži konfiguracijo &OK &V redu &Pause -&Pavza +&Premor &Quit &Zapri &Restore @@ -88,6 +90,8 @@ Na&loži konfiguracijo &Da (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Vedite, da samo na pogonih s FAT/FAT32 lahko pride do teh težav!\nV vseh drugih primerih lahko onemogoÄite nastavitev \"prezri 1-urno razliko\".) +(Requires an Internet connection!) +(Zahteva povezavo z Internetom!) , , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ Duplikat z druge strani od %name 1. &Primerjaj 1. Enter relative file or directory names separated by ';' or a new line. 1. Vnesite relativna imena datotek ali imenikov loÄenih z ';' ali novo vrstico. +1. Select directories to monitor. +1. Izberite imenike za nadziranje 2. &Synchronize... 2. &Sinhroniziraj... +2. Enter a command line. +2. Vnesite ukazno-vrstico. 2. Use wildcard characters '*' and '?'. 2. Uporabite lahko tudi znake '*' in '?'. 3. Exclude files directly on main grid via context menu. 3. IzkljuÄite datoteke neposredno na glavni mreži s kontekstnim menujem. +3. Press 'Start'. +3. Pritisnite 'ZaÄni'. <Automatic> <Samodejno> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Kot že samo ime pove, sta dve datoteki oznaÄeni kot enaki samo takrat, ko imata enako vsebino. Ta možnost je bolj uporabna za preverjanje doslednosti kot za operacije varnostnega shranjevanja. Zaradi tega se Äasi datotek ne upoÅ¡tevajo.\n\nZ omogoÄeno to možnostjo je drevo odloÄanja manjÅ¡e: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Sestavi batch datoteko za samodejno sinhronizacijo. Da zaÄnete v batch naÄinu, preprosto podajte ime batch datoteke k FreeFileSync izvrÅ¡ilni datoteki: FreeFileSync.exe <imedatotekebatch>. To se lahko nastavi tudi v urniku opravil vaÅ¡ega operacijskega sistema. +At least one directory input field is empty. +Vsaj eno vnosno polje za vpis imenika je prazno. Auto-adjust columns Samo-prilagodi stolpce Automatic mode @@ -192,19 +204,17 @@ Build: Izgradnja: Cancel PrekliÄi -Cannot determine sync-direction: Changed filter settings! -Ne morem doloÄiti smeri sinhronizacije: Spremenite nastavitve filtra! -Cannot determine sync-direction: No change since last synchronization! -Ne morem doloÄiti smeri sinhronizacije: Ni bilo sprememb od zadnje sinhronizacije! +Cannot determine sync-direction: +Ne morem doloÄiti sinhronizacijske smeri. Category Kategorija Change direction Spremeni smer Comma separated list Seznam loÄen z vejico -Commandline +Command line Ukazna vrstica -Commandline is empty! +Command line is empty! Ukazna vrstica je prazna! Compare Primerjaj @@ -260,8 +270,12 @@ Copy from right to left Kopiraj iz desne na levo Copy from right to left overwriting Kopiraj iz desne na levo s prepisovanjem +Copy locked files +Kopiraj zaklenjene datoteke Copy new or updated files to right folder. Kopiraj nove ali posodobljene datoteke v desno mapo. +Copy shared or locked files using Volume Shadow Copy Service. +Kopiraj deljene ali zaklenjene datoteke z uporabo servisa Volume Shadow Copy. Copy to clipboard\tCTRL+C Kopiraj v odložiÅ¡Äe\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Ne morem doloÄiti imena volumna za datoteko: Could not initialize directory monitoring: Ne morem zaÄeti nadzorovanja imenikov: +Could not load a required DLL: +Ne morem naložiti zahtevano DLL: Could not read values for the following XML nodes: Ne morem brati vrednosti za naslednja XML vozliÅ¡Äa: Create a batch job @@ -298,7 +314,7 @@ Date Datum Delay Zakasnitev -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Zakasnitev med zaznavo sprememb in izvrÅ¡itvijo ukazov v sekundah Delete files/folders existing on left side only IzbriÅ¡i datoteke/mape, ki obstajajo samo na levi strani @@ -386,6 +402,8 @@ Error reading file: Napaka pri branju datoteke: Error reading from synchronization database: Napaka pri branju iz sinhronizacijske podatkovne baze: +Error resolving full path name: +Napaka pri razreÅ¡evanju polnega imena poti: Error resolving symbolic link: Napaka pri razreÅ¡evanju simboliÄne povezave: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Filtriraj datoteke Filter has been selected Filter je bil izbran +Filter settings have changed! +Nastavitve filtra so bile spremenjene! Filter view Filtriran pogled Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows VkljuÄi se vrstice Include temporarily Trenutno vkljuÄi -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -VkljuÄi: *.doc;*.zip;*.exe\nIzkljuÄi: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +VkljuÄi: *.doc;*.zip;*.exe\nIzkljuÄi: \\stuff\\temp\\* Incompatible synchronization database format: Nekompatibilen format sinhronizacijske podatkovne baze: Info @@ -572,8 +592,6 @@ Initial synchronization: ZaÄetna sinhronizacija: Integrate external applications into context menu. The following macros are available: Integriraj zunanje aplikacije v kontekstni menu. Na voljo so naslednji makri: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Ni bilo mogoÄe inicializirati KoÅ¡a!\n\nZgleda, da ne uporabljate Windowsov.\nÄŒe želite imeti vkljuÄeno to lastnost, prosimo kontaktirajte avtorja. :) Leave as unresolved conflict Pusti kot nereÅ¡eni spor Left @@ -590,18 +608,22 @@ Log-messages: SporoÄila beleženja: Logging Beležim +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Ustvarjanje senÄnih kopij na WOW63 ni podprto. Prosimo uporabite 64-bitno FreeFileSync razliÄico. Mirror ->> Zrcalno ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Zrcalna kopija leve mape: Desna mapa bo prepisana in se bo natanÄno ujemala z levo mapo po sinhronizaciji. +Monitoring active... +Nadziranje aktivno... More than 50% of the total number of files will be copied or deleted! VeÄ kot 50% od celotnega Å¡tevila datotek bo kopiranih ali izbrisanih! Move column down Premakni stolpec dol Move column up Premakni stolpec gor -Move files to a user-defined directory. -Premakne datoteke v uporabniÅ¡ko-doloÄen imenik. +Move files into a time-stamped subdirectory. +Premakni datoteke v Äasovno-oznaÄen podimenik. Moving %x to Recycle Bin Premikam %x v KoÅ¡ Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y Premikam mapo %x v uporabniÅ¡ko-doloÄen imenik %y Multiple... VeÄkratno... +No change since last synchronization! +Ni sprememb od zadnje sinhronizacije! No filter selected Noben filter ni izbran Not enough free disk space available in: @@ -639,15 +663,13 @@ Operacija: Overview Pregled Pause -Pavza +Premor Paused -Na pavzi -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Prosim prekopirajte ustrezno \"Shadow.dll\" (ki se nahaja v \"Shadow.zip\" arhivu) v FreeFileSync namestitveni imenik, da omogoÄite to lastnost. -Please fill all empty directory fields. -Prosim izpolnite vse imenike s praznimi polji. +Na premoru Please run a Compare first before synchronizing! Prosim najprej zaženite Primerjaj preden sinhronizirate! +Processing folder pair: +Obdelujem par map: Published under the GNU General Public License: Objavljeno pod licenco GNU General Public: Question @@ -670,6 +692,8 @@ Remove folder pair Odstrani par imenikov Remove local filter settings Odstrani nastavitve lokalnega filtra +Renaming file %x to %y +Preimenujem datoteko %x v %y Report translation error PoroÄaj o napaki prevoda Reset @@ -786,6 +810,8 @@ Target directory already existing! Ciljni imenik že obstaja! Target file already existing! Ciljna datoteka že obstaja! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +Ta ukazna-vrstica se izvede vsakiÄ:\n- Datoteke znotraj teh imenikov (ali podimenikov) so spremenjene\n- Ustrezna Ärka pogona postane na razpolago (vstavitev USB-ja) The database file is not yet existing, but will be created during synchronization: Datoteka podatkovne baze Å¡e ne obstaja, ampak bo ustvarjena med sinhronizacijo: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Ne morem ustvariti datoteko za beleženje! Unable to initialize Recycle Bin! Ne morem inicializirati KoÅ¡a! +Unresolved conflicts existing! +Obstajajo nereÅ¡eni spori! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Obstajajo nereÅ¡eni spori! \n\nLahko ignorirate spore in nadaljujete s sinhronizacijo. Update -> Posodobi -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Uporaba: Izberite imenike za nadzorovanje in vnesite ukazno vrstico. VsakiÄ ko se spremenijo datoteke znotraj teh imenikov (ali podimenikov) se izvrÅ¡i ukazna vrstica. +Usage: +Uporaba: Use Recycle Bin Uporabi KoÅ¡ Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Pozor: Sinhronizacija ni uspela za %x predmetov: When the comparison is started with this option set the following decision tree is processed: Ko se primerjava zažene s tem setom možnosti, se obdela naslednje drevo odloÄitev: +You can ignore conflicts and continue synchronization. +Lahko ignorirate spore in nadaljujete s sinhronizacijo. You can ignore the error to consider not existing directories as empty. Ignoriraj napako za smatranje neobstojeÄih imenikv kot praznih. You can ignore the error to skip current folder pair. diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng index 466161c8..0c33f4bd 100644 --- a/BUILD/Languages/spanish.lng +++ b/BUILD/Languages/spanish.lng @@ -11,33 +11,33 @@ TB TB day(s) - + dia(s) hour(s) - + hora(s) kB kB min - + min sec - + seg %x / %y objects deleted successfully - +%x / %y objetos borrados satisfactoriamente %x Percent - +%x Por ciento %x directories %x directorios %x files, -%x ficheros, +%x archivos, %x is not a valid FreeFileSync batch file! - +%x no es un archivo batch de FreeFileSync válido! %x of %y rows in view -%x de %y ficheros +%x de %y filas en vista %x of 1 row in view -%x de 1 lÃnea +%x de 1 fila en vista &Abort &Abortar &About... -&Sobre... +&Acerca de... &Advanced &Avanzado &Apply @@ -45,17 +45,19 @@ &Cancel &Cancelar &Check for new version -&Buscar versión nueva +&Comprobar si existe una nueva versión +&Content +&Contenido &Create batch job -&Crear un fichero batch +&Crear un archivo batch &Default -&Config. por defecto +&Configuración por defecto &Exit - +&Salir &Export file list -&Exportar lista de ficheros +&Exportar lista de archivos &File -&Fichero +&Archivo &Global settings &Opciones globales &Help @@ -69,9 +71,9 @@ &Load configuration &Cargar configuración &New - +&Nuevo +&No &No - &OK &OK &Pause @@ -79,15 +81,17 @@ &Quit &Salir &Restore - +&Restaurar &Retry &Reintentar &Save &Guardar &Yes - +&Yes (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) - +(Tenga en cuenta que sólo las unidades FAT/FAT32 se ven afectadas por este problema!\nEn los demás casos puede deshabilitar la opción \"ignorar 1-hora de diferencia\".) +(Requires an Internet connection!) +(¡Conexión a Internet necesaria!) , , - Other side's counterpart to %dir @@ -95,139 +99,145 @@ - Other side's counterpart to %name - conflict - +- conflicto - conflict (same date, different size) - +- conflicto (misma fecha, distinto tamaño) - different -- ficheros diferentes +- diferentes - directory part only - +- sólo parte del directorio - equal -- ficheros iguales +- iguales - exists left only - existe sólo en la izquierda - exists right only - existe sólo en la derecha - full file or directory name - +- archivo completo o nombre del directorio - left - izquierda - left newer -- el más nuevo en la izquierda +- más reciente en la izquierda - right - derecha - right newer -- el más nuevo en la derecha +- más reciente en la derecha -Open-Source file synchronization- --Sincronización de ficheros Open-Source- +-Sincronización de archivos Open-Source- +. . -, /sec - +/seg 1 directory 1 directorio 1 file, -1 fichero, +1 archivo, 1. &Compare 1. &Comparar 1. Enter relative file or directory names separated by ';' or a new line. - +1. Introduzca los nombres de los archivos o directorios relativos separados por ';' o una nueva lÃnea. +1. Select directories to monitor. +1. Seleccione los directorios a visualizar. 2. &Synchronize... 2. &Sincronizar... +2. Enter a command line. +2. Introduzca una lÃnea de comando. 2. Use wildcard characters '*' and '?'. -2. Usar '*' y '?' como caracteres comodÃn. +2. Usar los caracteres comodÃn '*' y '?'. 3. Exclude files directly on main grid via context menu. -3. Excluir directamente ficheros sobre la rejilla a través del menu de contexto. +3. Excluir directamente archivos sobre las celdas a través del menú de contexto. +3. Press 'Start'. +3. Presione 'Inicio'. <Automatic> - +<Automático> <Directory> <Directorio> <Last session> <Última sesión> <multiple selection> -<Selección múltiple> +<selección múltiple> A newer version of FreeFileSync is available: - +Una nueva versión de FreeFileSync está disponible: Abort requested: Waiting for current operation to finish... -Abortar pedido: Esperar a que la actual operación finalice... +Solicitud de aborto: Esperando a que la operación actual finalice... Aborted Abortado About -Sobre +Acerca de Action Acción Activate filter - +Activar filtro Add folder - +Añadir carpeta Add folder pair Añadir un par de carpetas All directories in sync! - +¡Todos los directorios en sincronización! An exception occured! -¡Ha ocurrido una excepción! +¡Se ha producido una excepción! As a result the files are separated into the following categories: -Como resultado, los ficheros son separados en las siguientes categorÃas: +Como resultado, los archivos están separados en las siguientes categorÃas: As the name suggests, two files which share the same name are marked as equal if and only if they have the same content. This option is useful for consistency checks rather than backup operations. Therefore the file times are not taken into account at all.\n\nWith this option enabled the decision tree is smaller: -Como el nombre sugiere, dos ficheros que comparten el mismo nombre son marcados como iguales sólo si tienen el mismo contenido. Esta opción es útil para los chequeos de consistencia más que en operaciones de "backup". Por tanto, las fechas de los ficheros no se tienen en cuenta de ningún modo.\n\nCon esta opción habilitada el árbol de decisiones es más pequeño: +Como el tÃtulo sugiere, dos archivos que comparten el mismo nombre son marcados como iguales sólo si tienen el mismo contenido. Esta opción es útil para las comprobaciones de consistencia más que en operaciones de "backup". Por lo tanto, las fechas de los archivos no se tienen en cuenta.\n\nCon esta opción habilitada el árbol de decisiones se reduce a: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. -Crear un fichero "batch" para una sincronización automática. Para empezar en modo "batch" simplemente pasar el nombre del fichero al ejecutable FreeFileSyinc en la ventana de comandos (CMD): FreeFileSync.exe <nombre de fichero batch>. También puede ser planificada en el Administrador de Tareas programadas. +Crear un archivo batch para una sincronización automática. Para empezar en modo batch simplemente pasar el nombre del archivo por el ejecutable FreeFileSync en la ventana de comandos (CMD): FreeFileSync.exe <archivo batch>. También se puede planificar en el Administrador de Tareas de su Sistema Operativo. +At least one directory input field is empty. +Almenos un campo de entrada del directorio está vacÃo. Auto-adjust columns - +Ajustar automáticamente las columnas Automatic mode - +Modo automático Batch execution -Ejecución del "batch" +Ejecución batch Batch file created successfully! -¡El fichero "batch" ha sido creado correctamente! +¡El archivo batch ha sido creado correctamente! Batch job -Tarea Batch +Tarea batch Big thanks for localizing FreeFileSync goes out to: Agradecimientos por la traducción de FreeFileSync a: Both sides have changed since last synchronization! - +¡Ambos lados han cambiado desde la última sincronizacion! Browse - +Navegar Build: -ConstruÃdo: +Realizado: Cancel Cancelar -Cannot determine sync-direction: Changed filter settings! - -Cannot determine sync-direction: No change since last synchronization! - +Cannot determine sync-direction: +No se puede determinar la dirección de la sincronización: Category - +CategorÃa Change direction - +Cambiar dirección Comma separated list -Lista de "items" separados por coma -Commandline - -Commandline is empty! - +Lista separada por comas +Command line +LÃnea de comandos +Command line is empty! +¡La lÃnea de comandos está vacÃa! Compare - +Comparar Compare both sides Comparar ambos lados Compare by \"File content\" -Comparar por \"Contenido de fichero\" +Comparar por \"Contenido del archivo\" Compare by \"File size and date\" -Comparar por \"Tamaño y fecha de fichero\" +Comparar por \"Tamaño y fecha del archivo\" Compare by... Comparar por... Comparing content -Comparación de contenido +Comparación del contenido Comparing content of files %x -Comparación del contenido de %x ficheros +Comparación del contenido de %x archivos Comparing content... - +Comparando el contenido... Comparing files by content failed. - +La comparación de archivos por el contenido ha fallado. Comparison Result - +Resultado de la comparación Comparison settings - +Opciones de comparación Completed Terminado Configuration @@ -235,23 +245,23 @@ Configuración Configuration loaded! ¡Configuración cargada! Configuration overview: -Parámetros de configuración: +Visión global de la configuración: Configuration saved! ¡Configuración guardada! Configure filter Configurar filtro Configure your own synchronization rules. -Configure sus propias reglas de sincronización. +Configuración de sus propias reglas de sincronización. Confirm Confirmar Conflict detected: - +Conflicto detectado: Conflicts/files that cannot be categorized - +Conflictos/archivos que no pueden ser categorizados Continue Continuar Conversion error: -Erro de conversión: +Error de conversión: Copy from left to right Copiar de izquierda a derecha Copy from left to right overwriting @@ -260,22 +270,28 @@ Copy from right to left Copiar de derecha a izquierda Copy from right to left overwriting Copiar de derecha a izquierda con sobreescritura +Copy locked files +Copiar archivos bloqueados Copy new or updated files to right folder. -Copiar ficheros nuevos o actualizados a la carpeta de la derecha. +Copiar archivos nuevos o actualizados a la carpeta de la derecha. +Copy shared or locked files using Volume Shadow Copy Service. +Copiar archivos compartidos o bloqueados usando el servicio "Volume Shadow Copy". Copy to clipboard\tCTRL+C Copiar al Portapapeles\tCTRL+C Copying file %x to %y -Copiar fichero %x a %y +Copiar archivo %x a %y Copying file %x to %y overwriting target - +Copiar archivo %x a %y sobreescribiendo el objetivo Could not determine volume name for file: - +No se ha podido determinar el nombre del volumen para el archivo: Could not initialize directory monitoring: - +No se ha podido inicializar la visualización de directorios: +Could not load a required DLL: +No se ha podido cargar el DLL solicitado: Could not read values for the following XML nodes: - +No se ha podido leer los valores para los siguientes nodos XML: Create a batch job -Crear una tarea "batch" +Crear una tarea batch Creating folder %x Creando la carpeta %x Current operation: @@ -285,71 +301,71 @@ Personalizado Customize columns Personalizar columnas Customize... - +Personalizar... +D-Click D-Click - DECISION TREE ÃRBOL DE DECISIÓN Data remaining: Datos que faltan: Data verification error: Source and target file have different content! - +Error de verificación de datos: Los archivos origen y objetivo tienen un contenido diferente! Date Fecha Delay - -Delay between detection of changes and execution of commandline in seconds - +Retardo +Delay between detection of changes and execution of command line in seconds +Retardo entre la detección de cambios y la ejecución de la lÃnea de comandos en segundos Delete files/folders existing on left side only -Eliminar sólo ficheros/carpetas existentes en el lado izquierdo +Borrar sólo archivos/carpetas existentes en el lado izquierdo Delete files/folders existing on right side only -Eliminar sólo ficheros/carpetas existentes en el lado derecho +Borrar sólo archivos/carpetas existentes en el lado derecho Delete files\tDEL -Eliminar ficheros\tDEL +Borrar archivos\tDEL Delete on both sides -Eliminar en ambos lados lados +Borrar en ambos lados Delete on both sides even if the file is selected on one side only -Eliminar en ambos lados incluso si el fichero es seleccionado en un solo lado +Borrar en ambos lados incluso si el archivo está seleccionado en un solo lado Delete or overwrite files permanently. - +Borrar o sobreescribir archivos permanentemente. Delete permanently - +Borrar permanentemente Deleting file %x -Borrar fichero %x +Borrar archivo %x Deleting folder %x Borrar carpeta %x Deletion handling - +Gestión de eliminación Description - +Descripción Directories are dependent! Be careful when setting up synchronization rules: ¡Los directorios son dependientes! Cuidado al establecer las reglas de sincronización: Directories to watch - +Directorios a visualizar Directory - +Directorio Directory does not exist: El directorio no existe: Do not show this dialog again - +No volver a mostrar este diálogo Do nothing No hacer nada Do you really want to delete the following objects(s)? ¿Está seguro de querer borrar el/los siguiente(s) objeto(s)? Do you really want to move the following objects(s) to the Recycle Bin? -¿Está seguro de querer mover el/los siguiente(s) objeto(s) a la Papelera? +¿Está seguro de querer mover el/los siguiente(s) objeto(s) a la Papelera de Reciclaje? Do you want FreeFileSync to automatically check for updates every week? - +¿Quiere que FreeFileSync detecte automáticamente nuevas actualizaciones cada semana? Donate with PayPal -Donar usando PayPal +Donar a través de PayPal Download now? ¿Descargar ahora? Drag && drop -Arrastrar +Arrastrar && Soltar Email Email Enable filter to exclude files from synchronization - +Activar filtro para excluir archivos de la sincronización Endless loop when traversing directory: Error @@ -357,199 +373,203 @@ Error Error changing modification time: Error al modificar hora: Error copying file: -Erro al copiar fichero: +Error al copiar archivo: Error copying locked file %x! - +¡Error al copiar archivo bloqueado %x! Error creating directory: Error al crear directorio: Error deleting directory: Error al borrar directorio: Error deleting file: -Error al eliminar fichero: +Error al borrar archivo: Error handling -Controlador de errores +Gestión de errores Error loading library function: -Error al descargar función de biblioteca: +Error al cargar la función de biblioteca: Error moving directory: - +Error al mover directorio: Error moving file: - +Error al mover archivo: Error moving to Recycle Bin: -Error al mover a la Papelera: +Error al mover a la Papelera de Reciclaje: Error opening file: -Error al abrir fichero: +Error al abrir archivo: Error parsing configuration file: -Error en el análisis sintáctico del fichero de configuración: +Error en el análisis sintáctico del archivo de configuración: Error reading file attributes: -Error al leer atributos del fichero: +Error al leer atributos del archivo: Error reading file: -Error al leer el fichero: +Error al leer el archivo: Error reading from synchronization database: - +Error al leer de la base de datos de sincronización: +Error resolving full path name: +Error al resolver el nombre completo de ruta: Error resolving symbolic link: Error al resolver enlace simbólico: Error starting Volume Shadow Copy Service! - +¡Error al iniciar el servicio "Volume Shadow Copy"! Error traversing directory: -Error al trasladar directorio: -Error when monitoring directories. +Error when monitoring directories. +Error al visualizar los directorios. Error writing file attributes: -Error al escribir atributos del fichero: +Error al escribir atributos del archivos: Error writing file: -Error al escribir fichero: +Error al escribir archivo: Error writing to synchronization database: - +Error al escribir en la base de datos de sincronización: Example Ejemplo Exclude Excluir Exclude all rows - +Excluir todas las columnas Exclude temporarily Excluir temporalmente Exclude via filter: -Excluir por filtro: +Excluir a través del filtro: Exit immediately and set returncode < 0 -Salir inmediatamente y enviar el código < 0 +Salir inmediatamente y establecer el código de retorno < 0 Exit with RC < 0 -Salir com RC < 0 +Salir con RC < 0 External applications - +Aplicaciones externas Fatal Error - +Error fatal Feedback and suggestions are welcome at: -Los comentarios y sugerencias será bienvenidos en: +Comentarios y sugerencias son bienvenidos en: File %x has an invalid date! - +¡Archivo %x tiene una fecha inválida! File already exists. Overwrite? -El fichero ya existe. ¿Sustituir? +El archivo ya existe. ¿Sobreescribir? File content -Contenido del fichero +Contenido del archivo File does not exist: -El fichero no existe: +El archivo no existe: File list exported! -Lista de ficheros exportada! +¡Lista de archivos exportada! File size and date -Fecha y tamaño del fichero +Fecha y tamaño del archivo Filename -Nombre del fichero +Nombre del archivo Files %x have a file time difference of less than 1 hour!\n\nIt's not safe to decide which one is newer due to Daylight Saving Time issues. - +Los archivos %x tienen un archivo de tiempo diferente o menor que una hora!\n\nNo es seguro decidir cual de ellos es más reciente por cuestiones con el horario de verano. Files %x have the same date but a different size! - +¡Los archivos %x tienen la misma fecha pero un tamaño diferente! Files are found equal if\n - file content\nis the same. -Los ficheros serán considerados iguales si\n - el contenido del fichero\nes el mismo. +Los archivos serán considerados iguales si\n - el contenido del archivo\nes el mismo. Files are found equal if\n - filesize\n - last write time and date\nare the same. -Los ficheros serán considerados iguales si\n - la hora y fecha de la última escritura\nson iguales. +Los archivos serán considerados iguales si\n - tamaño del archivo\n - la hora y fecha de la última escritura\nson iguales. Files remaining: -Ficheros restantes: +Archivos restantes: Files that are equal on both sides - +Archivos que son iguales en ambos lados Files that exist on both sides and have different content -Ficheros que existen en ambos lados y tienen contenidos diferentes +Archivos que existen en ambos lados y tienen contenido diferente Files that exist on both sides, left one is newer -Ficheros que existen en ambos lados, el de la izquierda es más reciente +Archivos que existen en ambos lados, el de la izquierda es más reciente Files that exist on both sides, right one is newer -Ficheros que existen en ambos lados, el de la derecha es más reciente +Archivos que existen en ambos lados, el de la derecha es más reciente Files/folders found: - +Archivos/carpetas encontrados: Files/folders remaining: -Ficheros/carpetas restantes: +Archivos/carpetas restantes: Files/folders that exist on left side only -Ficheros/carpetas que existen sólo en el lado izquierdo +Archivos/carpetas que existen sólo en el lado izquierdo Files/folders that exist on right side only -Ficheros/carpetas que existen sólo en el lado derecho +Archivos/carpetas que existen sólo en el lado derecho Filter - +Filtro Filter files -Filtrar ficheros +Filtrar archivos Filter has been selected - +El filtro ha sido seleccionado +Filter settings have changed! +¡Las opciones de filtrado han cambiado! Filter view Vista de filtros Filtering is deactivated - +Filtrado desactivado Folder Comparison and Synchronization -Carpeta de Comparación y Sincronización +Comparación y Sincronización de carpetas Free disk space available: - +Espacio de disco libre disponible: FreeFileSync - Folder Comparison and Synchronization FreeFileSync - Comparación y Sincronización de carpetas FreeFileSync Batch Job -FreeFileSync Tarea "Batch" +FreeFileSync Tarea Batch FreeFileSync at Sourceforge FreeFileSync en Sourceforge FreeFileSync batch file -FreeFileSync fichero batch +FreeFileSync archivo batch FreeFileSync configuration FreeFileSync configuración FreeFileSync is up to date! -FreeFileSync está actualizado +¡FreeFileSync está actualizado! Full path - +Ruta completa Generating database... - +Generando base de datos... Generating file list... -Generando lista de ficheros... +Generando lista de archivos... Global filter - +Filtro global Global settings Opciones globales Help Ayuda Hidden dialogs: - +Diálogos ocultos: Hide all error and warning messages Ocultar todos los mensajes de error y aviso Hide conflicts - +Ocultar conflictos Hide excluded items - +Ocultar elementos excluidos Hide files that are different -Ocultar ficheros diferentes +Ocultar archivos diferentes Hide files that are equal -Ocultar ficheros iguales +Ocultar archivos iguales Hide files that are newer on left -Ocultar ficheros más recientes en la izquierda +Ocultar archivos más recientes en la izquierda Hide files that are newer on right -Ocultar ficheros más recientes en la derecha +Ocultar archivos más recientes en la derecha Hide files that exist on left side only -Ocultar los ficheros que existen sólo en el lado izquierdo +Ocultar archivos que existen sólo en el lado izquierdo Hide files that exist on right side only -Ocultar los ficheros que existen sólo en el lado derecho +Ocultar archivos que existen sólo en el lado derecho Hide files that will be created on the left side - +Ocultar archivos que serán creados en el lado izquierdo Hide files that will be created on the right side - +Ocultar archivos que serán creados en el lado derecho Hide files that will be deleted on the left side - +Ocultar archivos que serán eliminados en el lado izquierdo Hide files that will be deleted on the right side - +Ocultar archivos que serán eliminados en el lado derecho Hide files that will be overwritten on left side - +Ocultar archivos que serán sobreescritos en el lado izquierdo Hide files that will be overwritten on right side - +Ocultar archivos que serán sobreescritos en el lado derecho Hide files that won't be copied - +Ocultar archivos que no serán copiados Hide filtered or temporarily excluded files - +Ocultar archivos filtrados o temporalmente excluidos Hide further error messages during the current process -Ocultar próximos mensajes de error durante este processo +Ocultar próximos mensajes de error durante el proceso actual Hints: Consejos: Homepage -Homepage +Página de inicio Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. - +Identificar y aplicar cambios en ambos lados usando una base de datos. Los borrados y conflictos son detectados automáticamente. If you like FFS Si te gusta FFS Ignore 1-hour file time difference - +Ignorar el archivo de 1-hora de tiempo de diferencia Ignore errors Ignorar errores Ignore subsequent errors -Ignorar errores siguientes +Ignorar errores posteriores Ignore this error, retry or abort synchronization? ¿Ignorar este error, reintentar o abortar sincronización? Ignore this error, retry or abort? @@ -557,135 +577,139 @@ Ignore this error, retry or abort? Include Incluir Include all rows - +Incluir todas las filas Include temporarily Incluir temporalmente -Include: *.doc;*.zip;*.exe\nExclude: temp\\* - +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Incluir: *.doc;*.zip;*.exe\nExcluir: \\stuff\\temp\\* Incompatible synchronization database format: - +Formato de sincronización de base de datos incompatible: Info Info Information Información Initial synchronization: - +Sincronización inicial: Integrate external applications into context menu. The following macros are available: - -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -¡No fue posible iniciar la Papelera!\n\nEs probable que no esté usando Windows.\nSi quiere que este hecho sea considerado, por favor, contactate con el autor :) +Integrar aplicaciones externas en el menú de contexto. Las siguientes macros están disponibles: Leave as unresolved conflict - +Dejar como conflicto sin resolver Left - +Izquierda Legend - +Leyenda Load configuration from file -Cargar configuración desde fichero +Cargar configuración desde archivo Load configuration history (press DEL to delete items) -Cargar histórico de configuración (presionar DEL para borrar elementos) +Cargar historial de configuración (presionar DEL para borrar elementos) Local filter - +Filtro local Log-messages: -Log de mensajes: +Registro de mensajes: Logging - +Iniciando sesión +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La realización de copias shadow en WOW64 no está soportado. Por favor, use la versión de 64-bit de FreeFileSync. Mirror ->> Espejo ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Backup espejo de la carpeta de la izquierda: La carpeta de la derecha será sustituÃda y coincidirá exactamente con la carpeta de la izquierda después de la sincronización. +Monitoring active... +Visualización activa... More than 50% of the total number of files will be copied or deleted! - +¡Más del 50% del número total de archivos serán copiados o borrados! Move column down Mover columna abajo Move column up Mover columna arriba -Move files to a user-defined directory. - +Move files into a time-stamped subdirectory. +Mover archivos a un subdirectorio con marca de tiempo. Moving %x to Recycle Bin - +Mover %x a la Papelera de Reciclaje Moving file %x to user-defined directory %y - +Mover el archivo %x al directorio definido por el usuario %y. Moving folder %x to user-defined directory %y - +Mover la carpeta %x al directorio definido por el usuario %y. Multiple... - +Múltiple... +No change since last synchronization! +¡Ningún cambio desde la última sincronización! No filter selected - +Ningún filtro seleccionado Not enough free disk space available in: - +Espacio en disco disponible insuficiente en: Nothing to synchronize according to configuration! -¡No hay nada que sincronizar de acuerdo con la configuración! +¡Nada que sincronizar de acuerdo con la configuración! Number of files and directories that will be created -Número de elementos que serán creados +Número de archivos y directorios que serán creados Number of files and directories that will be deleted -Número de elementos que serán borrados +Número de archivos y directorios que serán borrados Number of files that will be overwritten -Número de ficheros que serán sustituÃdos +Número de archivos que serán sobreescritos OK OK Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the base synchronization directories. - +Sólo los archivos/directorios que pasen el filtrado serán seleccionados para la sincronización. El filtro será aplicado al nombre relativo(!) a la base de directorios de sincronización. Open directly - +Abrir directamente Open with Explorer - +Abrir con Explorer Open with Konqueror - +Abrir con Konqueror Operation aborted! -Operación abortada! +¡Operación abortada! Operation: Operación: Overview - +Visión global Pause Pausa Paused - -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. - -Please fill all empty directory fields. -Por favor, rellene todos los campos del directorio vacÃos. +Pausado Please run a Compare first before synchronizing! - +¡Por favor, ejecute la comparación antes de la sincronización! +Processing folder pair: +Procesar un par de carpetas: Published under the GNU General Public License: Publicado bajo "GNU General Public License": Question - +Pregunta Quit Salir Re-enable all hidden dialogs? - +¿Reactivar todos los diálogos ocultos? RealtimeSync - Automated Synchronization - +Sincronización automática de RealtimeSync RealtimeSync configuration - +Configuración de RealtimeSync Relative path -Camino relativo +Ruta relativa Remove alternate settings - +Eliminar opciones alternativas Remove folder - +Eliminar carpeta Remove folder pair -Eliminar par de carpetas +Eliminar un par de carpetas Remove local filter settings - +Eliminar las opciones locales de filtrado +Renaming file %x to %y +Renombrando archivo %x a %y Report translation error - +Informar de errores de traducción Reset Reiniciar Right - +Derecha Run minimized and write status information to a logfile - +Ejecutar minimizado y escribir información del estado en un archivo de registro S&ave configuration G&uardar configuración S&witch view - +C&ambiar vista Save changes to current configuration? - +¿Guardar los cambios de la configuración actual? Save current configuration to file -Guardar la configuración actual en un fichero +Guardar la configuración actual en un archivo Scanning... Analizando... Scanning: @@ -693,117 +717,119 @@ Analizar: Select a folder Seleccione una carpeta Select alternate synchronization settings - +Seleccione opciones alternativas de sincronización Select logfile directory: - +Seleccione directorio del archivo de registro: Select variant: -Sleccione una variante: +Seleccione un tipo: Setting default synchronization directions. Please check whether they are appropriate for you. - +Configurar direcciones de sincronización por defecto. Por favor, compruebe que son correctas. Show conflicts - +Mostrar conflictos Show file icons - +Mostrar icono de los archivos Show files that are different -Mostrar los ficheros diferentes +Mostrar archivos diferentes Show files that are equal -Mostrar los ficheros iguales +Mostrar archivos iguales Show files that are newer on left -Mostrar ficheros recientes a la izquierda +Mostrar archivos más recientes a la izquierda Show files that are newer on right -Mostrar ficheros recientes a la derecha +Mostrar archivos más recientes a la derecha Show files that exist on left side only -Mostrar ficheros existentes en la izquierda sólamente +Mostrar sólo archivos existentes en la izquierda Show files that exist on right side only -Mostrar ficheros existentes en la derecha sólamente +Mostrar sólo archivos existentes en la derecha Show files that will be created on the left side - +Mostrar archivos que serán creados en el lado izquierdo Show files that will be created on the right side - +Mostrar archivos que serán creados en el lado derecho Show files that will be deleted on the left side - +Mostrar archivos que serán eliminados en el lado izquierdo Show files that will be deleted on the right side - +Mostrar archivos que serán eliminados en el lado derecho Show files that will be overwritten on left side - +Mostrar archivos que serán sobreescritos en el lado izquierdo Show files that will be overwritten on right side - +Mostrar archivos que serán sobreescritos en el lado derecho Show files that won't be copied - +Mostrar archivos que no serán copiados Show hidden dialogs - +Mostrar diálogos ocultos Show popup -Mostrar "popups" +Mostrar popup Show popup on errors or warnings -Mostrar "popup" de errores o avisos +Mostrar popup de errores o avisos Significant difference detected: - +Diferencia significante detectada: Silent mode Modo silencioso Size Tamaño Source code written completely in C++ utilizing: -Código fuente escrito en C++ utilizando: +Código fuente escrito completamente en C++ utilizando: Source directory does not exist anymore: -El directorio origen no existe ya: +El directorio origen ya no existe: Speed: - +Velocidad: Start Iniciar Start synchronization -Iniciar a sincronización +Iniciar sincronización Statistics - +EstadÃstica Stop -Parar +Detener Swap sides - +Intercambiar lados Synchronization Preview - +Previsualización de la sincronización Synchronization aborted! -Sincronización abortada! +¡Sincronización abortada! Synchronization completed successfully! ¡Sincronización completada con éxito! Synchronization completed with errors! ¡Sincronización completada con errores! Synchronization settings -Parámetros de sincronización +Opciones de sincronización Synchronization status Estado de la sincronización Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". - +Sincronizar todos los archivos .doc, .zip and .exe excepto el contenido de la subcarpeta \"temp\". Synchronize both sides simultaneously: Copy new or updated files in both directions. -Sincronizar ambos lados simultáneamente: Copiar ficheros nuevos o actualizados en ambas direcciones. +Sincronizar ambos lados simultáneamente: Copiar archivos nuevos o actualizados en ambas direcciones. Synchronize both sides using a database. Deletions are detected automatically. - +Sincronizar ambos lados usando una base de datos. Los borrados son detectados automáticamente. Synchronize... - +Sincronizar... Synchronizing... Sincronizando... System out of memory! -Sistema sin memoria! +¡Sistema sin memoria! Target directory already existing! - +¡El directorio objetivo ya existe! Target file already existing! -¡El fichero objetivo existe ya! +¡El archivo objetivo ya existe! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +La lÃnea de comandos es ejecutada cada vez:\n- Archivos con estos directorios (o subdirectorios) son modificados\n- La letra de la unidad correspondiente se muestra disponible (inserción USB) The database file is not yet existing, but will be created during synchronization: - +El archivo de base de datos no existe aún pero será creado durante la sincronización: The file does not contain a valid configuration: -El fichero no contiene una configuración válida: +El archivo no contiene una configuración válida: The required database entry is not yet existing, but will be created during synchronization: - +La entrada a la base de datos no existe aún pero será creada durante la sincronización: This variant evaluates two equally named files as being equal when they have the same file size AND the same last write date and time. -Esta variante evalúa dos ficheros con el mismo nombre como iguales cuando tienen el mismo tamaño Y la misma fecha de modificación. +Este tipo evalúa dos archivos con el mismo nombre como iguales cuando tienen el mismo tamaño de archivo y la misma fecha de modificación. Time Hora Time elapsed: Tiempo transcurrido: Time remaining: - +Tiempo restante: Total amount of data that will be transferred Cantidad total de datos que serán transferidos Total required free disk space: - +Espacio total de disco necesario: Total time: Tiempo total: Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. @@ -811,46 +837,50 @@ Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as Two way <-> Doble sentido <-> Unable to connect to sourceforge.net! -Permitir conectar con sourceforge.net +¡Incapaz de conectar con sourceforge.net! Unable to create logfile! -Permitir crear logfile +¡Incapaz de crear un archivo de registro! Unable to initialize Recycle Bin! -Permitir iniciar la Papelera +¡Incapaz de iniciar la Papelera de Reciclaje! +Unresolved conflicts existing! +¡Existen conflictos sin resolver! Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Update -> Actualizar -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. - +Usage: +Uso: Use Recycle Bin -Utilizar la Papelera +Utilizar Papelera de Reciclaje Use Recycle Bin when deleting or overwriting files. - +Utilitzar Papelera de Reciclaje al borrar o sobreescribir archivos. User-defined directory - +Directorio definido por el usuario User-defined directory for deletion was not specified! - +¡El directorio definido por el usuario para el borrado no ha sido indicado! Variant - +Tipo Verifying file %x - +Verificación del archivo %x Volume name %x not part of filename %y! - +El nombre del volumen %x no es una parte del nombre del archivo %y Warning Atención Warning: Synchronization failed for %x item(s): Atención: La sincronización falló para %x item(s): When the comparison is started with this option set the following decision tree is processed: -Cuando la comparación se inicia con este conjunto de opciones, se procesa el siguiente árbol de decisiones: +Cuando la comparación se inicia con este conjunto de opciones se procesa el siguiente árbol de decisiones: +You can ignore conflicts and continue synchronization. +Puede ignorar conflictos y continuar con la sincronización. You can ignore the error to consider not existing directories as empty. - +Puede ignorar el error al considerar que no existen directorios como vacÃos. You can ignore the error to skip current folder pair. - +Puede ignorar el error omitiendo el par de carpetas actuales. You may try to synchronize remaining items again (WITHOUT having to re-compare)! -Puede intentar sincronizar los elementos restantes otra vez (SIN tener que volver a comparar) +¡Puede intentar sincronizar los elementos restantes otra vez (SIN tener que volver a comparar)! different -ficheros diferentes +diferentes file exists on both sides -el fichero existe en ambos lados +el archivo existe en ambos lados on one side only -fichero sólo en un lado +sólo en un lado diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng new file mode 100644 index 00000000..9211ce99 --- /dev/null +++ b/BUILD/Languages/swedish.lng @@ -0,0 +1,886 @@ + MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI framework\n wxFormBuilder\t- wxWidgets GUI-builder\n CodeBlocks \t- Open-Source IDE + MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI Framework\n wxFormBuilder\t- wxWidgets GUI-Builder\n CodeBlocks \t- Open-Source IDE + Byte + Byte + GB + GB + MB + MB + PB + PB + TB + TB + day(s) + dag(ar) + hour(s) + timma(r) + kB + kB + min + min. + sec + sek. +%x / %y objects deleted successfully +%x / %y objekt borttagna +%x Percent +%x Procent +%x directories +%x kataloger +%x files, +%x filer, +%x is not a valid FreeFileSync batch file! +%x är ingen giltig FreeFileSync batch-fil! +%x of %y rows in view +%x rader av %y i vyn +%x of 1 row in view +%x av 1 rad i vyn +&Abort +&Avbryt +&About... +&Om... +&Advanced +&Avancerat +&Apply +&Verkställ +&Cancel +&Avbryt +&Check for new version +&Sök efter uppdatering +&Content +&InnehÃ¥ll +&Create batch job +&Skapa batch-jobb +&Default +&Standard +&Exit +&Avsluta +&Export file list +&Exportera fillista +&File +&Arkiv +&Global settings +&Allmäna inställningar +&Help +&Hjälp +&Ignore +&Ignorera +&Language +&SprÃ¥k +&Load +&Läs frÃ¥n fil +&Load configuration +&Hämta inställningar frÃ¥n fil +&New +&Nytt +&No +&Nej +&OK +&OK +&Pause +&Paus +&Quit +&Sluta +&Restore +&Ã…terställ +&Retry +&Försök igen +&Save +&Spara +&Yes +&Ja +(Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) +(Notera att endast FAT/FAT32-formaterade diskar berörs av detta problem!\nI alla andra fall kan du inaktivera alternativet \"Ignorera sommartid\".) +(Requires an Internet connection!) +(Kräver Internetuppkoppling!) +, +. +- Other side's counterpart to %dir +- Andra sidans motsvarighet till %dir +- Other side's counterpart to %name +- Andra sidans motsvarighet till %name +- conflict +- konflikt +- conflict (same date, different size) +- konflikt (samma datum, olika storlek) +- different +- olika +- directory part only +- Endast fil-/katalognamn +- equal +- lika +- exists left only +- finns endast till vänster +- exists right only +- finns endast till höger +- full file or directory name +- Full sökväg +- left +- vänster +- left newer +- vänster nyare +- right +- höger +- right newer +- höger nyare +-Open-Source file synchronization- +-Öppen källkod filsynkronisering- +. +, +/sec +/s +1 directory +1 katalog +1 file, +1 fil, +1. &Compare +1. &Jämför +1. Enter relative file or directory names separated by ';' or a new line. +1. Ange fil- eller katalognamn avgränsade med "," eller en ny rad +1. Select directories to monitor. +1. Välj kataloger att övervaka. +2. &Synchronize... +2. &Synkronisera... +2. Enter a command line. +2. Mata in ett kommando. +2. Use wildcard characters '*' and '?'. +2. Använd wildcard-tecknen '*' och '?' . +3. Exclude files directly on main grid via context menu. +3. Undanta filer direkt i huvudfönstret, via högerklicksmenyn. +3. Press 'Start'. +3. Tryck 'Start'. +<Automatic> +<Automatisk> +<Directory> +<Katalog> +<Last session> +<Senaste session> +<multiple selection> +<flerval> +A newer version of FreeFileSync is available: +En nyare version av FreeFileSync finns tillgänglig: +Abort requested: Waiting for current operation to finish... +Avbryter: Väntar pÃ¥ att aktuell process skall slutföras... +Aborted +Användaren avbröt +About +Om +Action +Aktivitet +Activate filter +Aktivera filter +Add folder +Lägg till katalog +Add folder pair +Lägg till katalogpar +All directories in sync! +Alla kataloger synkade! +An exception occured! +Ett undantag inträffade! +As a result the files are separated into the following categories: +Som ett resultat blir filerna separerade i följande kategorier: +As the name suggests, two files which share the same name are marked as equal if and only if they have the same content. This option is useful for consistency checks rather than backup operations. Therefore the file times are not taken into account at all.\n\nWith this option enabled the decision tree is smaller: +Som namnet antyder, tvÃ¥ filer med samma namn beräknas som lika, endast om dom har samma innehÃ¥ll. Den här funktionen är mer användbar för konsistenskontroll, snarare än säkerhetskopiering. Därför tas inte tidsattributen med i beräkningen.\n\nMed det här alternativet aktiverat, blir beslutsträdet mindre: +Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. +Montera en batch-fil för automatisk synkronisering. För att starta i batch-läge, lägg till filnamnet i startkommandot: FreeFileSync.exe <batch-fil>. Det kan ocksÃ¥ schemaläggas i Windows Schemaläggaren. +At least one directory input field is empty. +Minst 1 adressfält är tomt. +Auto-adjust columns +Autojustera kollumner +Automatic mode +Autoläge +Batch execution +Batch-körning +Batch file created successfully! +Batch-filen skapades korrekt! +Batch job +Batch-jobb +Big thanks for localizing FreeFileSync goes out to: +Stort tack för översättningen av FreeFileSync gÃ¥r till: +Both sides have changed since last synchronization! +BÃ¥da sidor har ändrats sedan senaste synkroniseringen! +Browse +Bläddra +Build: +Bygg: +Cancel +Avbryt +Cannot determine sync-direction: +Kan inte bestämma synk-riktning: +Category +Kategori +Change direction +Ändra riktning +Comma separated list +Komma-separerad lista +Command line +Kommandofält +Command line is empty! +Kommandofältet är tomt +Compare +Jämför +Compare both sides +Jämför bÃ¥da sidor +Compare by \"File content\" +Jämför: \"FilinnehÃ¥ll\" +Compare by \"File size and date\" +Jämför: \"Filstorlek och datum\" +Compare by... +Jämför... +Comparing content +Jämför innehÃ¥ll +Comparing content of files %x +Jämför filinnehÃ¥ll för %x +Comparing content... +Jämför innehÃ¥ll... +Comparing files by content failed. +Kunde inte jämföra filinnehÃ¥ll. +Comparison Result +Jämförelseresultat +Comparison settings +Jämförelseinställningar +Completed +Klar +Configuration +Inställningar +Configuration loaded! +Inställningar inlästa! +Configuration overview: +Översikt: +Configuration saved! +Inställningar sparade! +Configure filter +Filterinställningar +Configure your own synchronization rules. +Konfigurera dina egna synkroniseringsregler. +Confirm +Bekräfta +Conflict detected: +Konflikt upptäckt: +Conflicts/files that cannot be categorized +Konflikter/filer som inte kan kategoriseras +Continue +Fortsätt +Conversion error: +Konversionsfel: +Copy from left to right +Kopiera frÃ¥n vänster till höger +Copy from left to right overwriting +Kopiera frÃ¥n vänster till höger och skriv över mÃ¥let +Copy from right to left +Kopiera frÃ¥n höger till vänster +Copy from right to left overwriting +Kopiera frÃ¥n höger till vänster och skriv över mÃ¥let +Copy locked files +Kopiera lÃ¥sta filer +Copy new or updated files to right folder. +Kopiera nya och uppdaterade filer till höger katalog. +Copy shared or locked files using Volume Shadow Copy Service. +Använd Volume Shadow Copy Service för att kopiera lÃ¥sta eller delade filer. +Copy to clipboard\tCTRL+C +Kopiera till urklipp\tCTRL+C +Copying file %x to %y +Kopierar fil %x till %y +Copying file %x to %y overwriting target +Kopierar fil %x till %y skriver över mÃ¥let +Could not determine volume name for file: +Kan inte bestämma volym för fil: +Could not initialize directory monitoring: +Kan inte initiera katalogskanner: +Could not load a required DLL: +Kan inte läsa in nödvändig DLL: +Could not read values for the following XML nodes: +Kan inte läsa värden för följande XML-noder: +Create a batch job +Skapa ett batch-jobb +Creating folder %x +Skapar katalog %x +Current operation: +Aktuell uppgift: +Custom +Anpassat +Customize columns +Anpassa kollumner +Customize... +Anpassar... +D-Click +HÃ¥ll ner D +DECISION TREE +BESLUTSTRÄD +Data remaining: +Ã…terstÃ¥ende data: +Data verification error: Source and target file have different content! +Verifikationsfel: Källfil och mÃ¥lfil har olika innehÃ¥ll! +Date +Datum +Delay +Fördröjning +Delay between detection of changes and execution of command line in seconds +Fördröjning mellan ändringars upptäckt och Ã¥tgärd i sekunder +Delete files/folders existing on left side only +Ta bort filer/kataloger som endast finns pÃ¥ vänster sida +Delete files/folders existing on right side only +Ta bort filer/kataloger som endast finns pÃ¥ höger sida +Delete files\tDEL +Ta bort filer\tDEL +Delete on both sides +Ta bort pÃ¥ bÃ¥da sidor +Delete on both sides even if the file is selected on one side only +Ta bort pÃ¥ bÃ¥da sidor, även om filen är markerad pÃ¥ endast en sida +Delete or overwrite files permanently. +Ta bort eller skriv över permanent +Delete permanently +Ta bort permanent +Deleting file %x +Tar bort filen %x +Deleting folder %x +Tar bort katalogen %x +Deletion handling +Borttagning +Description +Beskrivning +Directories are dependent! Be careful when setting up synchronization rules: +Kataloger är beroende! Var försiktig när du sätter upp synkroniseringsregler: +Directories to watch +Kataloger att övervaka +Directory +Katalog +Directory does not exist: +Katalogen finns inte: +Do not show this dialog again +Visa inte den här dialogrutan igen +Do nothing +Gör ingenting +Do you really want to delete the following objects(s)? +Vill du verkligen ta bort följande objekt? +Do you really want to move the following objects(s) to the Recycle Bin? +Vill du verkligen flytta följande objekt till papperskorgen? +Do you want FreeFileSync to automatically check for updates every week? +Vill du att FreeFileSync skall söka efter uppdateringar varje vecka? +Donate with PayPal +Donera via PayPal +Download now? +Ladda ner nu? +Drag && drop +Dra && släpp +Email +e-post +Enable filter to exclude files from synchronization +Aktivera filter för att undanta filer frÃ¥n synkronisering +Endless loop when traversing directory: +Oändlig loop vid accessförsök pÃ¥ katalog: +Error +Fel +Error changing modification time: +Kan inte modifiera tidsstämpel: +Error copying file: +Kan inte kopiera fil: +Error copying locked file %x! +Kan inte kopiera lÃ¥st fil %x! +Error creating directory: +Kan inte skapa katalog: +Error deleting directory: +Kan inte ta bort katalog: +Error deleting file: +Kan inte ta bort fil: +Error handling +Felhantering +Error loading library function: +Kan inte starta biblioteksfunktion: +Error moving directory: +Kan inte flytta katalog: +Error moving file: +Kan inte flytta fil: +Error moving to Recycle Bin: +Kan inte flytta till papperskorgen: +Error opening file: +Kan inte öppna fil: +Error parsing configuration file: +Kan inte läsa in konfigurationsfil: +Error reading file attributes: +Kan inte läsa filattribut: +Error reading file: +Kan inte läsa fil: +Error reading from synchronization database: +Kan inte läsa frÃ¥n databasen: +Error resolving full path name: +Kan inte läsa in full sökväg: +Error resolving symbolic link: +Kan inte tyda symbolisk länk: +Error starting Volume Shadow Copy Service! +Kan inte starta 'Volume Shadow Copy Service'! +Error traversing directory: +Accessfel pÃ¥ katalog: +Error when monitoring directories. +Fel vid övervakning av kataloger. +Error writing file attributes: +Kan inte skriva filattribut: +Error writing file: +Kan inte skriva fil: +Error writing to synchronization database: +Kan inte skriva till databas: +Example +Exempel +Exclude +Undanta +Exclude all rows +Undanta alla rader +Exclude temporarily +Undanta tillfälligt +Exclude via filter: +Lägg till i undantag: +Exit immediately and set returncode < 0 +Avsluta omedelbart och sätt returkod < 0 +Exit with RC < 0 +Avsluta med RC < 0 +External applications +Externa program +Fatal Error +Allvarligt fel +Feedback and suggestions are welcome at: +Feedback och förslag är välkommna här: +File %x has an invalid date! +Filen %x har ett ogiltigt datum! +File already exists. Overwrite? +Filen finns redan. Vill du skriva över: +File content +FilinnehÃ¥ll +File does not exist: +Filen finns inte: +File list exported! +Fillista exporterad! +File size and date +Filstorlek och datum +Filename +Filnamn +Files %x have a file time difference of less than 1 hour!\n\nIt's not safe to decide which one is newer due to Daylight Saving Time issues. +Filerna %x har en tidsstämpling som skiljer mindre än en timme!\n\nDet är inte helt säkert att avgöra vilken som är nyast, p.g.a sommartids-problem. +Files %x have the same date but a different size! +Filerna %x har samma datum men olika storlek! +Files are found equal if\n - file content\nis the same. +Filerna betecknas som lika om, \n - filinnehÃ¥llet\när lika. +Files are found equal if\n - filesize\n - last write time and date\nare the same. +Filerna betecknas som lika om, \n - filstorlek\n - 'senast använd' och datum\när lika. +Files remaining: +Filer kvar: +Files that are equal on both sides +Filer som är lika pÃ¥ bÃ¥da sidor +Files that exist on both sides and have different content +Filer som finns pÃ¥ bÃ¥da sidor och har olika innehÃ¥ll +Files that exist on both sides, left one is newer +Filer som finns pÃ¥ bÃ¥da sidor, vänster är nyare +Files that exist on both sides, right one is newer +Filer som finns pÃ¥ bÃ¥da sidor, höger är nyare +Files/folders found: +Funna filer/kataloger: +Files/folders remaining: +Filer/kataloger kvar: +Files/folders that exist on left side only +Filer/kataloger som finns pÃ¥ vänster sida enbart +Files/folders that exist on right side only +Filer/kataloger som finns pÃ¥ höger sida enbart +Filter +Filter +Filter files +Undantag +Filter has been selected +Filter aktiverat +Filter settings have changed! +Filterinställningar har ändrats! +Filter view +Filtervy +Filtering is deactivated +Filter inaktiverat +Folder Comparison and Synchronization +Katalogjämförelse och synkronisering +Free disk space available: +Ledigt diskutrymme: +FreeFileSync - Folder Comparison and Synchronization +FreeFileSync - Jämför och Synkronisera +FreeFileSync Batch Job +FreeFileSync Batch-jobb +FreeFileSync at Sourceforge +FreeFileSync pÃ¥ Sourceforge +FreeFileSync batch file +FreeFileSync batch-fil +FreeFileSync configuration +FreeFileSync konfiguration +FreeFileSync is up to date! +FreeFileSync är uppdaterad! +Full path +Fullständig sökväg +Generating database... +Skapar databas... +Generating file list... +Skapar fillista... +Global filter +Allmänt filter +Global settings +Allmäna inställningar +Help +Hjälp +Hidden dialogs: +Dolda meddelanden: +Hide all error and warning messages +Visa inte fel- och varningsmeddelanden +Hide conflicts +Visa inte konflikter +Hide excluded items +Visa inte undantagna objekt +Hide files that are different +Visa inte filer som är olika +Hide files that are equal +Visa inte filer som är lika +Hide files that are newer on left +Visa inte filer som är nyare till vänster +Hide files that are newer on right +Visa inte filer som är nyare till höger +Hide files that exist on left side only +Visa inte filer som endast finns till vänster +Hide files that exist on right side only +Visa inte filer som endast finns till höger +Hide files that will be created on the left side +Visa inte filer som kommer att skapas pÃ¥ vänster sida +Hide files that will be created on the right side +Visa inte filer som kommer att skapas pÃ¥ höger sida +Hide files that will be deleted on the left side +Visa inte filer som kommer att tas bort pÃ¥ vänster sida +Hide files that will be deleted on the right side +Visa inte filer som kommer att tas bort pÃ¥ höger sida +Hide files that will be overwritten on left side +Visa inte filer som kommer att skrivas över pÃ¥ vänster sida +Hide files that will be overwritten on right side +Visa inte filer som kommer att skrivas över pÃ¥ höger sida +Hide files that won't be copied +Visa inte filer som som inte kopieras +Hide filtered or temporarily excluded files +Visa inte filtrerade eller temporärt undantagna filer +Hide further error messages during the current process +Dölj vidare felmeddelanden under aktuell process +Hints: +LedtrÃ¥d: +Homepage +Hemsida +Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. +Identifiera och visa förändringar pÃ¥ bÃ¥da sidor via databas. Borttagningar och konflikter upptäcks automatiskt. +If you like FFS +Om du gillar FFS +Ignore 1-hour file time difference +Ignorera sommartid +Ignore errors +Ignorera fel +Ignore subsequent errors +Ignorera följdfel +Ignore this error, retry or abort synchronization? +Ignorera felet, försök igen eller avbryt synkroniseringen? +Ignore this error, retry or abort? +Ignorera felet, försök igen eller avbryt? +Include +Inkludera +Include all rows +Inkludera alla rader +Include temporarily +Inkludera tillfälligt +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Inkludera: *.doc;*.zip;*.exe\nUndanta: \\stuff\\temp\\* +Incompatible synchronization database format: +Inkompatibelt databasformat: +Info +Info +Information +Information +Initial synchronization: +Initial synkronisering: +Integrate external applications into context menu. The following macros are available: +Integrera externa program i högerklicksmeny. Följande variabler finns tillgängliga: +Leave as unresolved conflict +Ignorera konflikt +Left +Vänster +Legend +Förklaring +Load configuration from file +Hämta inställningar frÃ¥n fil +Load configuration history (press DEL to delete items) +Konfigurationshistoria (Tryck DEL för att ta bort objekt) +Local filter +Lokalt filter +Log-messages: +Log-meddelanden: +Logging +Loggar +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Skuggkopior av wow64 stöds ej. Använd FreeFileSync x64 istället! +Mirror ->> +Spegla ->> +Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. +Speglad kopia av vänster sida: Höger sida kommer att skrivas över med en exakt kopia av vänster sida. +Monitoring active... +Övervakning aktiverad... +More than 50% of the total number of files will be copied or deleted! +mer än 50% av totalt filantal kommer att kopieras eller tas bort! +Move column down +Flytta ner kollumn +Move column up +Flytta upp kollumn +Move files into a time-stamped subdirectory. +Flytta filer till en tidsstämplad underkatalog +Moving %x to Recycle Bin +Flyttar %x till papperskorgen +Moving file %x to user-defined directory %y +Flyttar %x till %y +Moving folder %x to user-defined directory %y +Flyttar %x till %y +Multiple... +Multipla... +No change since last synchronization! +Inga ändringar sedan senaste synkronisering! +No filter selected +Inga filter aktiverade +Not enough free disk space available in: +Ej tillräckligt ledigt diskutrymme pÃ¥: +Nothing to synchronize according to configuration! +Inget att synkronisera enligt aktuella inställningar! +Number of files and directories that will be created +Antal filer och kataloger som kommer att skapas +Number of files and directories that will be deleted +Antal filer och kataloger som kommer att tas bort +Number of files that will be overwritten +Antal filer som kommer att skrivas över +OK +OK +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the base synchronization directories. +Endast filer/kataloger som kvarstÃ¥r efter filtrering, kommer att markeras för synkronisering. +Open directly +Öppna fil +Open with Explorer +Öppna katalog +Open with Konqueror +Öppna med Konqueror +Operation aborted! +Processen avbruten! +Operation: +Arbetsuppgift: +Overview +Översikt +Pause +Paus +Paused +Pausad +Please run a Compare first before synchronizing! +Du mÃ¥ste trycka \"Jämför\" innan du kan synkronisera. +Processing folder pair: +Processar katalogpar: +Published under the GNU General Public License: +Publiserad under GNU General Public License: +Question +FrÃ¥ga +Quit +Avsluta +Re-enable all hidden dialogs? +Ã…teraktivera alla dolda meddelanden? +RealtimeSync - Automated Synchronization +RealtimeSync - Automatiserad synkronisering +RealtimeSync configuration +RealtimeSync konfiguration +Relative path +Sökväg +Remove alternate settings +Ta bort alternativa inställningar +Remove folder +Ta bort katalog +Remove folder pair +Ta bort katalogpar +Remove local filter settings +Ta bort lokala filterinställningar +Renaming file %x to %y +Byter namn pÃ¥ %x till %y +Report translation error +Rapportera översättningsfel +Reset +Ã…terställ +Right +Höger +Run minimized and write status information to a logfile +Kör minimerad och skriv statusinformation till loggfil +S&ave configuration +S¶ inställningar +S&witch view +B&yt sida +Save changes to current configuration? +Vill du spara ändringarna i aktuella inställningar? +Save current configuration to file +Spara aktuella inställningar till fil +Scanning... +Skannar... +Scanning: +Skannar: +Select a folder +Markera en katalog +Select alternate synchronization settings +Välj alternativa synkroniseringsinställningar +Select logfile directory: +Välj loggfilsdestination: +Select variant: +Välj variant: +Setting default synchronization directions. Please check whether they are appropriate for you. +Kontrollera om standard synkroniseringskataloger passar dina önskemÃ¥l. +Show conflicts +Visa konflikter +Show file icons +Visa filikoner +Show files that are different +Visa filer som är olika +Show files that are equal +Visa filer som är lika +Show files that are newer on left +Visa filer som är nyare till vänster +Show files that are newer on right +Visa filer som är nyare till höger +Show files that exist on left side only +Visa filer som endast finns till vänster +Show files that exist on right side only +Visa filer som endast finns till höger +Show files that will be created on the left side +Visa filer som kommer att skapas till vänster +Show files that will be created on the right side +Visa filer som kommer att skapas till höger +Show files that will be deleted on the left side +Visa filer som kommer att tas bort till vänster +Show files that will be deleted on the right side +Visa filer som kommer att tas bort till höger +Show files that will be overwritten on left side +Visa filer som skrivas över till vänster +Show files that will be overwritten on right side +Visa filer som skrivas över till höger +Show files that won't be copied +Visa filer som inte kommer att kopieras +Show hidden dialogs +Visa dolda meddelanden +Show popup +Visa popups +Show popup on errors or warnings +Visa popup vid fel eller varningar +Significant difference detected: +Betydande skillnad upptäckt: +Silent mode +Tyst läge +Size +Storlek +Source code written completely in C++ utilizing: +Source code written completely in C++ utilizing: +Source directory does not exist anymore: +Källkatalogen finns inte längre: +Speed: +Hastighet: +Start +Start +Start synchronization +Starta synkronisering +Statistics +Statistik +Stop +Stopp +Swap sides +Byt sida +Synchronization Preview +Förhandsvisning +Synchronization aborted! +Synkronisering avbruten! +Synchronization completed successfully! +Synkronisering slutförd! +Synchronization completed with errors! +Synkronisering slutförd med fel! +Synchronization settings +Synkroniseringsinställningar +Synchronization status +Synkroniseringsstatus +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Synkronisera alla filer, .doc, .zip och .exe men inga undermappar \"temp\". +Synchronize both sides simultaneously: Copy new or updated files in both directions. +Synkronisera bÃ¥da sidor simultant: Kopiera nya eller uppdaterade filer i bägge riktningar. +Synchronize both sides using a database. Deletions are detected automatically. +Synkronisera bÃ¥da sidor med hjälp av databas. Borttagningar upptäcks automatiskt. +Synchronize... +Synkronisera +Synchronizing... +Synkroniserar... +System out of memory! +Systemminnet är fullt! +Target directory already existing! +MÃ¥lkatalogen finns redan! +Target file already existing! +Filen finns redan! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) +Kommandot kommer att exekveras varje gÃ¥ng:\n- InnehÃ¥llet i dessa kataloger (eller underkataloger) ändras\n- Enheten med aktuell enhetsbokstav ansluts (USB-anslutning) +The database file is not yet existing, but will be created during synchronization: +Databasfilen finns inte ännu, men kommer att skapas under synkroniseringen. +The file does not contain a valid configuration: +Filen är ingen giltig konfigureringsfil: +The required database entry is not yet existing, but will be created during synchronization: +Databasobjektet finns inte ännu, men kommer att skapas under synkroniseringen: +This variant evaluates two equally named files as being equal when they have the same file size AND the same last write date and time. +Denna variant betecknar 2 filer med samma namn som lika, när dom har samma storlek OCH samma tidsstämpling. +Time +Tid +Time elapsed: +Förfluten tid: +Time remaining: +Kvarvarande tid: +Total amount of data that will be transferred +Total mängd data som kommer att överföras +Total required free disk space: +Ledigt diskutrymme som krävs: +Total time: +Total tid: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Betrakta tidsstämplar som skiljer exakt +/- 1 timme som lika, och mindre än 1 timme som konflikt, för att hantera sommartid. +Two way <-> +Bägge riktningar <-> +Unable to connect to sourceforge.net! +Kan inte ansluta sourceforge.net! +Unable to create logfile! +Kan inte skapa loggfil! +Unable to initialize Recycle Bin! +Kan inte initiera papperskorgen! +Unresolved conflicts existing! +Obehandlad konflikt upptäckt! +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Obehandlad konflikt upptäckt! \n\nDu kan ignorera konflikter och fortsätta synkroniseringen. +Update -> +Uppdatera -> +Usage: +Användning: +Use Recycle Bin +Använd papperskorgen +Use Recycle Bin when deleting or overwriting files. +Use Volume Shadow Copy Service to copy locked or shared files. +User-defined directory +Användardefinierad katalog +User-defined directory for deletion was not specified! +Katalog för borttagning ej specifiserad! +Variant +Variant +Verifying file %x +Verifierar %x +Volume name %x not part of filename %y! +Volymnamn %x saknas i filnamn %y! +Warning +Varning +Warning: Synchronization failed for %x item(s): +Varning: Synkronisering misslyckades för %x objekt: +When the comparison is started with this option set the following decision tree is processed: +När jämförelse startas med detta alternativ aktiverat, processas följande beslutsträd: +You can ignore conflicts and continue synchronization. +Du kan ignorera konflikter och fortsätta synkroniseringen. +You can ignore the error to consider not existing directories as empty. +Du kan ignorera felet att inte betrakta befintliga kataloger som tomma. +You can ignore the error to skip current folder pair. +Du kan ignorera felet att hoppa över aktuellt katalogpar. +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +Du kan försöka synkronisera Ã¥terstÃ¥ende objekt igen (utan att trycka \"Jämför\")! +different +olika +file exists on both sides +Filen finns pÃ¥ bÃ¥da sidor +on one side only +endast pÃ¥ en sida diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng index 8b548066..3bc006f1 100644 --- a/BUILD/Languages/turkish.lng +++ b/BUILD/Languages/turkish.lng @@ -46,6 +46,8 @@ Va&zgeç &Ä°ptal &Check for new version &Yeni sürüm kontrolü yap +&Content + &Create batch job &Komut (batch) görevi oluÅŸtur &Default @@ -88,6 +90,8 @@ Ge&ri yükle &Evet (Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Not: Sadece FAT/FAT32 olarak biçimlendirilmiÅŸ sürücüler bu problemden etkilenir!\nDiÄŸer durumlarda, \"1-saat'lik zaman farkını yoksay\" ayarı devre dışı bırakılabilir.) +(Requires an Internet connection!) + , , - Other side's counterpart to %dir @@ -132,12 +136,18 @@ Ge&ri yükle 1. &KarşılaÅŸtır 1. Enter relative file or directory names separated by ';' or a new line. 1. ';' ile ayırarak veya herbiri yeni satırda olacak ÅŸekilde göreceli (relatif) dosya veya dizin adlarını girin. +1. Select directories to monitor. + 2. &Synchronize... 2. &Senkronize et... +2. Enter a command line. + 2. Use wildcard characters '*' and '?'. 2. Joker karakter olan '*' ve '?' kullan. 3. Exclude files directly on main grid via context menu. 3. SaÄŸ fare tuÅŸu ile açılan menüden ana listedeki dosyaları direk olarak hariç tutun. +3. Press 'Start'. + <Automatic> <Otomatik> <Directory> @@ -172,6 +182,8 @@ As the name suggests, two files which share the same name are marked as equal if Ä°smindende anlaşılacağı gibi, aynı isme sahip iki dosya sadece ve sadece aynı içeriÄŸe sahipse eÅŸit olarak iÅŸaretlenir. Bu seçenek yedekleme iÅŸlemlerinden daha ziyade uyuÅŸma kontrolü için faydalıdır. Bu yüzden dosya tarihleri hiç bir zaman dikkate alınmaz.\n\nBu seçenek etkinleÅŸtirildiÄŸinde karar ÅŸeması küçülür: Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. Otomatik senkronizasyon için bir komut (batch) dosyası oluÅŸturun. Komut modunda baÅŸlamak için, komut dosyasını parametre olarak tanımlayarak FreeFileSync'i çalıştırın: FreeFileSync.exe <Komut Dosyası Adı>. Bu komut dosyası, istenirse, iÅŸletim sistemindeki görev zamanlayıcı ile istenilen zamanlarda çalıştırılabilir. +At least one directory input field is empty. + Auto-adjust columns Kolonları otomatik olarak hizala Automatic mode @@ -192,20 +204,18 @@ Build: Derleme: Cancel Ä°ptal -Cannot determine sync-direction: Changed filter settings! -Senkronizasyon yönü belirlenemiyor: Filtre ayarlarý deðiþmiþ! -Cannot determine sync-direction: No change since last synchronization! -Senkronizasyon yönü belirlenemiyor: En son senkronizasyondan beri deðiþiklik yok! +Cannot determine sync-direction: + Category Kategori Change direction Yönü deÄŸiÅŸtir Comma separated list Virgül ile ayrılmış liste -Commandline +Command line Komut satırı -Commandline is empty! -Komut satırı boÅŸ! +Command line is empty! + Compare KarşılaÅŸtır Compare both sides @@ -260,8 +270,12 @@ Copy from right to left SaÄŸdan sola kopyala Copy from right to left overwriting SaÄŸdan sola üzerine yazmaya izin vererek kopyala +Copy locked files + Copy new or updated files to right folder. Yeni veya güncellenmiÅŸ dosyaları saÄŸdaki klasöre kopyala. +Copy shared or locked files using Volume Shadow Copy Service. + Copy to clipboard\tCTRL+C Hafızaya kopyala\tCTRL+C Copying file %x to %y @@ -272,6 +286,8 @@ Could not determine volume name for file: Belirtilen dosya için birim adı belirlenemedi: Could not initialize directory monitoring: Dizin izlemesi baÅŸlatılamadı: +Could not load a required DLL: + Could not read values for the following XML nodes: Takibeden XML baÅŸlığındaki deÄŸerler okunamadı: Create a batch job @@ -298,7 +314,7 @@ Date Tarih Delay Gecikme -Delay between detection of changes and execution of commandline in seconds +Delay between detection of changes and execution of command line in seconds Saniye olarak, deÄŸiÅŸikliklerin tespiti ile komut satırının çalıştırılması arasındaki boÅŸluk süresi Delete files/folders existing on left side only Sadece sol tarafta olan dosyaları/klasörleri sil @@ -386,6 +402,8 @@ Error reading file: Dosyayı okurken hata: Error reading from synchronization database: Senkronizasyon veri tabanýndan okuma hatasý: +Error resolving full path name: + Error resolving symbolic link: Sembolik baÄŸlantıyı çözümlerken hata: Error starting Volume Shadow Copy Service! @@ -466,6 +484,8 @@ Filter files Fltre dosyaları Filter has been selected +Filter settings have changed! + Filter view Filtre görünümü Filtering is deactivated @@ -560,8 +580,8 @@ Include all rows Include temporarily Geçici olarak dahil et -Include: *.doc;*.zip;*.exe\nExclude: temp\\* -Dahil et: *.doc;*.zip;*.exe\nHariç tut: temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\* +Dahil et: *.doc;*.zip;*.exe\nHariç tut: \\stuff\\temp\\* Incompatible synchronization database format: Uyumsuz senkronizasyon veritabaný formatý: Info @@ -572,8 +592,6 @@ Initial synchronization: Baþlangýç senkronizasyonu: Integrate external applications into context menu. The following macros are available: Harici uygulamaları içerik menüsüne ekle. Åžu makro’lar temin edilebilir: -It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) -Geri dönüşüm kutusunu baÅŸlatmak mümkün olmadı!\n\nMuhtemelen Microsoft Windows kullanmıyorsunuz.\nEÄŸer bu özelliÄŸin eklenmesini istiyorsanız, lütfen program yazarı ile temasa geçin. :) Leave as unresolved conflict ÇözülmemiÅŸ tutarsızlık olarak bırak Left @@ -590,18 +608,22 @@ Log-messages: Kayıt mesajları: Logging Kayıt tutma +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. + Mirror ->> Yedekleme ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Sol klasörün yedeklemesi: Senkronizasyondan sonra sol klasör ile tam olarak eÅŸleÅŸen saÄŸ klasörün üzerine yazılacak. +Monitoring active... + More than 50% of the total number of files will be copied or deleted! %50’den fazla dosya kopyalanacak veya silinecek! Move column down Kolonu aÅŸağı taşı Move column up Kolonu yukarı taşı -Move files to a user-defined directory. -Dosyaları kullanıcı tanımlı bir dizine taşı. +Move files into a time-stamped subdirectory. + Moving %x to Recycle Bin %x geri dönüşüm kutusuna taşınıyor Moving file %x to user-defined directory %y @@ -610,6 +632,8 @@ Moving folder %x to user-defined directory %y %x klasörü kullanıcı tanımlı dizin %y’e taşınıyor Multiple... Çoklu... +No change since last synchronization! + No filter selected Not enough free disk space available in: @@ -642,12 +666,10 @@ Pause Duraklat Paused Duraklatıldı -Please copy the appropriate \"Shadow.dll\" (located in \"Shadow.zip\" archive) into the FreeFileSync installation directory to enable this feature. -Bu özelliÄŸi etkinleÅŸtirmek için FreeFileSync’in kurulum dizinine \"Shadow.dll\" (\"Shadow.zip\" sıkıştırılmış dosyasındaki uygun olanı) kopyalayın. -Please fill all empty directory fields. -Lütfen boÅŸ dizin alanlarını doldurunuz. Please run a Compare first before synchronizing! +Processing folder pair: + Published under the GNU General Public License: “GNU General Public Licenseâ€a uygun olarak yayımlanmıştır: Question @@ -670,6 +692,8 @@ Remove folder pair Klasör çiftini kaldır Remove local filter settings +Renaming file %x to %y + Report translation error Çeviri hatasını bildir Reset @@ -786,6 +810,8 @@ Target directory already existing! Hedef dizin zaten mevcut! Target file already existing! Hedef dosya zaten mevcut! +The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert) + The database file is not yet existing, but will be created during synchronization: The file does not contain a valid configuration: @@ -816,12 +842,14 @@ Unable to create logfile! Kayıt dosyası yaratılamıyor! Unable to initialize Recycle Bin! Geri dönüşüm kutusu baÅŸlatılamıyor! +Unresolved conflicts existing! + Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. Çözülemeyen tutarsızlık mevcut! \n\nTutarsızlıkları yoksayıp senkronizasyona devam edebilirsiniz. Update -> Güncelle -> -Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed. -Kullanım: Ä°zleme için dizinleri seç ve bir komut satırı ver. Bu dizinlerdeki (veya alt dizinlerdeki) dosyalar deÄŸiÅŸikliÄŸe her uÄŸradığında, girilen komut satırı çalıştırılacaktır. +Usage: + Use Recycle Bin Geri dönüşüm kutusunu kullan Use Recycle Bin when deleting or overwriting files. @@ -842,6 +870,8 @@ Warning: Synchronization failed for %x item(s): Uyarı: %x kadar öğe için senkronizasyon baÅŸarısız oldu: When the comparison is started with this option set the following decision tree is processed: Bu opsiyonla karşılaÅŸtırma baÅŸlatıldığı zaman, takibeden karar ÅŸemasının iÅŸleme konacağını tanımla: +You can ignore conflicts and continue synchronization. + You can ignore the error to consider not existing directories as empty. Var olamayan dizinleri boÅŸ olarak tanımlama hatasını yoksay. You can ignore the error to skip current folder pair. diff --git a/BUILD/Resources.dat b/BUILD/Resources.dat Binary files differindex 481a9f0f..ff81f194 100644 --- a/BUILD/Resources.dat +++ b/BUILD/Resources.dat diff --git a/BUILD/Sync_Complete.wav b/BUILD/Sync_Complete.wav Binary files differindex a6a9cc84..f166cc4b 100644 --- a/BUILD/Sync_Complete.wav +++ b/BUILD/Sync_Complete.wav diff --git a/BUILD/mingwm10.dll b/BUILD/mingwm10.dll Binary files differdeleted file mode 100644 index 9e609264..00000000 --- a/BUILD/mingwm10.dll +++ /dev/null diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp index cad9426e..fc06b084 100644 --- a/FreeFileSync.cbp +++ b/FreeFileSync.cbp @@ -147,6 +147,7 @@ <Unit filename="library\customGrid.h"> <Option target="<{~None~}>" /> </Unit> + <Unit filename="library\detectRenaming.h" /> <Unit filename="library\errorLogging.cpp"> <Option target="Debug" /> <Option target="Release" /> @@ -230,6 +231,7 @@ <Option target="Debug" /> <Option target="Release" /> </Unit> + <Unit filename="shared\Recycler.h" /> <Unit filename="shared\appMain.cpp"> <Option target="Debug" /> <Option target="Release" /> @@ -238,6 +240,7 @@ <Option target="Debug" /> <Option target="Release" /> </Unit> + <Unit filename="shared\buildInfo.h" /> <Unit filename="shared\customButton.cpp"> <Option target="Debug" /> <Option target="Release" /> @@ -269,6 +272,8 @@ <Unit filename="shared\fileError.h" /> <Unit filename="shared\fileHandling.cpp" /> <Unit filename="shared\fileHandling.h" /> + <Unit filename="shared\fileID.cpp" /> + <Unit filename="shared\fileID.h" /> <Unit filename="shared\fileTraverser.cpp" /> <Unit filename="shared\fileTraverser.h" /> <Unit filename="shared\globalFunctions.cpp" /> @@ -277,6 +282,10 @@ <Unit filename="shared\guid.h" /> <Unit filename="shared\localization.cpp" /> <Unit filename="shared\localization.h" /> + <Unit filename="shared\longPathPrefix.cpp" /> + <Unit filename="shared\longPathPrefix.h" /> + <Unit filename="shared\recycler.cpp" /> + <Unit filename="shared\recycler.h" /> <Unit filename="shared\serialize.cpp" /> <Unit filename="shared\serialize.h" /> <Unit filename="shared\shadow.cpp" /> diff --git a/FreeFileSync.vcproj b/FreeFileSync.vcproj index 6bf06d87..9af3ce87 100644 --- a/FreeFileSync.vcproj +++ b/FreeFileSync.vcproj @@ -70,7 +70,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib winmm.lib" - OutputFile="BUILD\$(ProjectName).exe" + OutputFile="BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateManifest="true" @@ -130,7 +130,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";.\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";.\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -147,7 +147,7 @@ <Tool Name="VCResourceCompilerTool" Culture="0" - AdditionalIncludeDirectories="D:\Programme\C++\wxWidgets-x64\include;D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" + AdditionalIncludeDirectories="C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" /> <Tool Name="VCPreLinkEventTool" @@ -155,9 +155,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib winmm.lib" - OutputFile="BUILD\$(ProjectName).exe" + OutputFile="BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateManifest="true" GenerateDebugInformation="true" SubSystem="2" @@ -239,7 +239,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib winmm.lib" - OutputFile="BUILD\$(ProjectName).exe" + OutputFile="BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateDebugInformation="false" @@ -300,12 +300,13 @@ Optimization="2" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";.\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";.\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="4" + SuppressStartupBanner="false" DebugInformationFormat="3" DisableSpecificWarnings="4804;4100" /> @@ -315,7 +316,7 @@ <Tool Name="VCResourceCompilerTool" Culture="1033" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" /> <Tool Name="VCPreLinkEventTool" @@ -323,9 +324,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib winmm.lib" - OutputFile="BUILD\$(ProjectName).exe" + OutputFile="BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" @@ -425,6 +426,10 @@ > </File> <File + RelativePath=".\shared\fileID.cpp" + > + </File> + <File RelativePath=".\shared\fileTraverser.cpp" > </File> @@ -461,6 +466,10 @@ > </File> <File + RelativePath=".\shared\longPathPrefix.cpp" + > + </File> + <File RelativePath=".\ui\mainDialog.cpp" > </File> @@ -469,6 +478,10 @@ > </File> <File + RelativePath=".\shared\recycler.cpp" + > + </File> + <File RelativePath=".\library\resources.cpp" > </File> @@ -45,6 +45,7 @@ FILE_LIST+=shared/customButton.cpp FILE_LIST+=shared/toggleButton.cpp FILE_LIST+=shared/customComboBox.cpp FILE_LIST+=shared/serialize.cpp +FILE_LIST+=shared/fileID.cpp #list of all *.o files OBJECT_LIST=$(foreach file, $(FILE_LIST), OBJ/$(subst .cpp,.o,$(notdir $(file)))) diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index d15a5ab2..76eccb5e 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -128,11 +128,15 @@ <Unit filename="..\shared\fileError.h" /> <Unit filename="..\shared\fileHandling.cpp" /> <Unit filename="..\shared\fileHandling.h" /> + <Unit filename="..\shared\fileID.cpp" /> <Unit filename="..\shared\fileTraverser.cpp" /> <Unit filename="..\shared\globalFunctions.cpp" /> <Unit filename="..\shared\globalFunctions.h" /> <Unit filename="..\shared\localization.cpp" /> <Unit filename="..\shared\localization.h" /> + <Unit filename="..\shared\longPathPrefix.cpp" /> + <Unit filename="..\shared\longPathPrefix.h" /> + <Unit filename="..\shared\recycler.cpp" /> <Unit filename="..\shared\shadow.cpp" /> <Unit filename="..\shared\standardPaths.cpp" /> <Unit filename="..\shared\standardPaths.h" /> diff --git a/RealtimeSync/RealtimeSync.vcproj b/RealtimeSync/RealtimeSync.vcproj index f3501a17..ddf293ea 100644 --- a/RealtimeSync/RealtimeSync.vcproj +++ b/RealtimeSync/RealtimeSync.vcproj @@ -69,7 +69,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateManifest="true" @@ -129,7 +129,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";..\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";..\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -145,7 +145,7 @@ <Tool Name="VCResourceCompilerTool" Culture="0" - AdditionalIncludeDirectories="D:\Programme\C++\wxWidgets-x64\include;D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" + AdditionalIncludeDirectories="C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" /> <Tool Name="VCPreLinkEventTool" @@ -153,9 +153,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateManifest="true" GenerateDebugInformation="true" SubSystem="2" @@ -237,7 +237,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateDebugInformation="false" @@ -298,12 +298,13 @@ Optimization="2" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";..\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";..\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" + SuppressStartupBanner="false" DebugInformationFormat="3" DisableSpecificWarnings="4804" /> @@ -313,7 +314,7 @@ <Tool Name="VCResourceCompilerTool" Culture="1033" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" /> <Tool Name="VCPreLinkEventTool" @@ -321,9 +322,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" @@ -383,6 +384,10 @@ > </File> <File + RelativePath="..\shared\fileID.cpp" + > + </File> + <File RelativePath="..\shared\fileTraverser.cpp" > </File> @@ -403,6 +408,10 @@ > </File> <File + RelativePath="..\shared\longPathPrefix.cpp" + > + </File> + <File RelativePath=".\mainDialog.cpp" > </File> @@ -411,6 +420,10 @@ > </File> <File + RelativePath="..\shared\recycler.cpp" + > + </File> + <File RelativePath=".\resources.cpp" > </File> diff --git a/RealtimeSync/RealtimeSync.xpm b/RealtimeSync/RealtimeSync.xpm deleted file mode 100644 index 557ef973..00000000 --- a/RealtimeSync/RealtimeSync.xpm +++ /dev/null @@ -1,312 +0,0 @@ -/* XPM */ -static const char* RealtimeSync_xpm[] = { -"32 32 277 2", -" c None", -"! c black", -"# c #2A0404", -"$ c #330505", -"% c #3D0707", -"& c #360606", -"' c #340606", -"( c #500909", -") c #630B0B", -"* c #890F0F", -"+ c #AC1414", -", c #AB1414", -"- c #9F1212", -". c #820F0F", -"0 c #510909", -"1 c #2F0505", -"2 c #530A0A", -"3 c #8B1010", -"4 c #E83E3E", -"5 c #F39494", -"6 c #F6ADAD", -"7 c #F49B9B", -"8 c #F07E7E", -"9 c #EC5C5C", -": c #E73636", -"; c #D71818", -"< c #AD1414", -"= c #7C0E0E", -"> c #410707", -"? c #E73232", -"@ c #FACECE", -"A c #FCDFDF", -"B c #F7B8B8", -"C c #F39090", -"D c #EF6E6E", -"E c #EA4D4D", -"F c #E72D2D", -"G c #E41E1E", -"H c #E31F1F", -"I c #E52121", -"J c #E31C1C", -"K c #670C0C", -"L c #380606", -"M c #420808", -"N c #6D0C0C", -"O c #F07777", -"P c #FEEEEE", -"Q c #F9C6C6", -"R c #F49D9D", -"S c #EC5D5D", -"T c #E83C3C", -"U c #E62121", -"V c #E41A1A", -"W c #E41D1D", -"X c #E21E1E", -"Y c #E41C1C", -"Z c #E51C1C", -"[ c #C71717", -"] c #720C0C", -"^ c #330606", -"_ c #640C0C", -"` c #EF7171", -"a c #FCE3E3", -"b c #F6AFAF", -"c c #F28D8D", -"d c #E72E2E", -"e c #E62020", -"f c #E51A1A", -"g c #E51F1F", -"h c #CA1818", -"i c #680C0C", -"j c #260404", -"k c #4F0909", -"l c #540A0A", -"m c #520909", -"n c #E72F2F", -"o c #FAD3D3", -"p c #F4A0A0", -"q c #F17E7E", -"r c #ED5E5E", -"s c #E93E3E", -"t c #E62525", -"u c #E51B1B", -"v c #BD1616", -"w c #941111", -"x c #810E0E", -"y c #830F0F", -"z c #991111", -"{ c #E21A1A", -"| c #B41515", -"} c #420707", -"~ c #8C1010", -" ! c #E62323", -"!! c #C91717", -"#! c #B21515", -"$! c #EB5050", -"%! c #E73030", -"&! c #DC1919", -"'! c #250404", -"(! c #550A0A", -")! c #7B0E0E", -"*! c #BC1616", -"+! c #860F0F", -",! c #310505", -"-! c #3F0707", -".! c #F07676", -"0! c #EB5656", -"1! c #E62727", -"2! c #E62424", -"3! c #E21D1D", -"4! c #DE1919", -"5! c #7A0E0E", -"6! c #470808", -"7! c #350606", -"8! c #5B0A0A", -"9! c #971111", -":! c #DF1919", -";! c #BF1616", -"<! c #951111", -"=! c #EA4E4E", -">! c #E61F1F", -"?! c #E41B1B", -"@! c #E31A1A", -"A! c #D41919", -"B! c #8D1010", -"C! c #5D0B0B", -"D! c #390606", -"E! c #1F0303", -"F! c #4E0909", -"G! c #D61818", -"H! c #750D0D", -"I! c #270404", -"J! c #6A0C0C", -"K! c #E62222", -"L! c #C81717", -"M! c #790D0D", -"N! c #290404", -"O! c #460808", -"P! c #770D0D", -"Q! c #D81818", -"R! c #A21212", -"S! c #E52020", -"T! c #931111", -"U! c #7D0E0E", -"V! c #A61313", -"W! c #450808", -"X! c #3A0606", -"Y! c #570A0A", -"Z! c #2E0505", -"[! c #440808", -"]! c #580A0A", -"^! c #630C0C", -"_! c #BA1616", -"`! c #D51818", -"a! c #180202", -"b! c #EC5959", -"c! c #F39292", -"d! c #3C0707", -"e! c #DF1A1A", -"f! c #6C0C0C", -"g! c #300505", -"h! c #D11818", -"i! c #FFFEFE", -"j! c white", -"k! c #FCDDDD", -"l! c #8A1010", -"m! c #D41818", -"n! c #A91313", -"o! c #730D0D", -"p! c #1D0303", -"q! c #4B0909", -"r! c #AF1414", -"s! c #F39797", -"t! c #FFFBFB", -"u! c #FFFAFA", -"v! c #FDEBEB", -"w! c #FCDEDE", -"x! c #FBD4D4", -"y! c #FBDADA", -"z! c #EB4E4E", -"{! c #880F0F", -"|! c #200303", -"}! c #600B0B", -"~! c #F9CBCB", -" # c #FBD7D7", -"!# c #F8BEBE", -"## c #F5A5A5", -"$# c #F49C9C", -"%# c #F39191", -"&# c #F28989", -"'# c #F07B7B", -"(# c #A71313", -")# c #700D0D", -"*# c #140202", -"+# c #E73333", -",# c #F5A8A8", -"-# c #F39393", -".# c #F18282", -"0# c #F07878", -"1# c #EE6C6C", -"2# c #ED6262", -"3# c #EC5757", -"4# c #E94242", -"5# c #E94141", -"6# c #DA1919", -"7# c #F38E8E", -"8# c #690C0C", -"9# c #760D0D", -":# c #EC5A5A", -";# c #EA4949", -"<# c #E93F3F", -"=# c #E62626", -"># c #DD1919", -"?# c #6F0C0C", -"@# c #2C0505", -"A# c #FEEBEB", -"B# c #F07D7D", -"C# c #6B0C0C", -"D# c #911010", -"E# c #D21818", -"F# c #E31B1B", -"G# c #E11D1D", -"H# c #400707", -"I# c #EE6666", -"J# c #7F0E0E", -"K# c #5C0B0B", -"L# c #E62828", -"M# c #B11414", -"N# c #F39A9A", -"O# c #ED6565", -"P# c #A31313", -"Q# c #370606", -"R# c #840F0F", -"S# c #E21B1B", -"T# c #E31D1D", -"U# c #B61515", -"V# c #ED6161", -"W# c #EB5555", -"X# c #490808", -"Y# c #3B0707", -"Z# c #650C0C", -"[# c #9E1212", -"]# c #E41F1F", -"^# c #E51D1D", -"_# c #800E0E", -"`# c #921111", -"a# c #4A0808", -"b# c #320505", -"c# c #E73535", -"d# c #E72A2A", -"e# c #E72B2B", -"f# c #E42020", -"g# c #B11515", -"h# c #E51E1E", -"i# c #E31E1E", -"j# c #530909", -"k# c #E42121", -"l# c #610B0B", -"m# c #4D0909", -"n# c #DB1A1A", -"o# c #AA1414", -"p# c #620B0B", -"q# c #720D0D", -"r# c #B31515", -"s# c #E11919", -"t# c #C61717", -"u# c #5A0A0A", -"v# c #BB1616", -"w# c #CC1818", -"x# c #C11717", -"y# c #850F0F", -"z# c #1E0303", -"{# c #2B0505", -"|# c #560A0A", -"}# c #5F0B0B", -"~# c #210303", -" $ c #170202", -" ", -" # $ % & # ", -" ' ( ) * + , - . ) 0 $ ", -" 1 2 3 4 5 6 7 8 9 : ; < = 2 # ", -" > ) ? @ A B C D E F G H I J < K L ", -" M N O P Q R 8 S T U V W X Y Z I [ ] & ", -" ^ _ ` a b c D E d e G f Y g e W Y f h i j ", -" k l l m 2 n o p q r s t u v w x y z v { f f f | 2 ", -"} ~ d !!!#!q C ` $!%!g &!~ 0 1 '!j L (!)!*!f f f +!,! ", -"-!*!.!0!4 1!Y 2!d 2!3!4!5!6! 7!8!9!:!f ;!2 ", -"% <!=!: >!?!V @!{ V W A!B!C!D! E!F!x G!f H!E! ", -"I!J!e K!?!f ?!u ?!J f f f L!M!N! O!P!Q!R!1 ", -" l < S!f ?!u ?!J f f f f f T!# } U!V!W! ", -" X!= V Z u ?!J f f f f f + Y! Z![!]!^!]! ", -" 8!_!I ?!J f f f f `!T!0 a! ,!Y!#!b!c!;!l ", -" d!P!e!Z f f f 4!+ f!X! g!]!h!R i!j!j!k!l!& ", -" 2 +!{ f m!n!o!W!p! q!r!s!t!u!v!w!x!y!z!Y! ", -" O!]!x {!_ > |! }!F ~! #!#b ##$#%#&#'#~ X! ", -" & (#)#6!*# 8!+#,#-#.#0#1#2#3#=!4#5#;!(! ", -" '!6#7#8#Z! 9#S :#;#<#: F =#I Z 3!Y >#?#@# ", -" U!A#B#C#X! m D#E#X F#G#V G#F#J Y 3!Y T!H# ", -" ( 2#y!I#J#O! W!K#v L#Y J f f f f f f M#0 ", -" ,!r!$#N#O#P#]!Q# W!R#S#U T#?!T#X ?!V f f U#Y! ", -" 8!? 1#V#W#h!y C!X#Y#q!Z#[#S#]#W G ^#G ?!* _#`#w P!a# ", -" b#J#? c#d#e#f#h g#+ | `!g h#Y Y i#Y f V!j#^ & D!' ", -" 6!l!J h#J W k#U K!U ]#Y ?!f f f f U#l#g! ", -" m#{!n#e h#i#J u f f f f f f f o#p#X! ", -" W!q#r#s#f f f f f f f f t#{!u#b# ", -" Z!2 P!- v#w#G!h!x#o#y#p#O!z# ", -" {#> |#}#p#}!8!m#X!~# ", -" $ $ ", -" "};
\ No newline at end of file diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp index b974fb89..68cebae0 100644 --- a/RealtimeSync/application.cpp +++ b/RealtimeSync/application.cpp @@ -13,6 +13,7 @@ #include "../shared/localization.h" #include "xmlFreeFileSync.h" #include "../shared/standardPaths.h" +#include <wx/file.h> #ifdef FFS_LINUX #include <gtk/gtk.h> @@ -80,3 +81,30 @@ void Application::OnStartApplication(wxIdleEvent& event) frame->SetIcon(*GlobalResources::getInstance().programIcon); //set application icon frame->Show(); } + + +bool Application::OnExceptionInMainLoop() +{ + throw; //just re-throw exception and avoid display of additional exception messagebox: it will be caught in OnRun() +} + + +int Application::OnRun() +{ + try + { + wxApp::OnRun(); + } + catch (const std::exception& e) //catch all STL exceptions + { + //unfortunately it's not always possible to display a message box in this erroneous situation, however (non-stream) file output always works! + wxFile safeOutput(FreeFileSync::getLastErrorTxtFile(), wxFile::write); + safeOutput.Write(wxString::FromAscii(e.what())); + + wxMessageBox(wxString::FromAscii(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR); + return -9; + } + + return 0; //program's return value +} + diff --git a/RealtimeSync/application.h b/RealtimeSync/application.h index e7116156b..d95cb3b4 100644 --- a/RealtimeSync/application.h +++ b/RealtimeSync/application.h @@ -16,11 +16,13 @@ class Application : public wxApp { public: virtual bool OnInit(); + virtual int OnRun(); + virtual bool OnExceptionInMainLoop(); private: void OnStartApplication(wxIdleEvent& event); - std::auto_ptr<wxHelpController> helpController; //global help controller + std::auto_ptr<wxHelpController> helpController; //global help controller }; #endif // REALTIMESYNCAPP_H diff --git a/RealtimeSync/functions.h b/RealtimeSync/functions.h index 3d7d522f..0001a7ec 100644 --- a/RealtimeSync/functions.h +++ b/RealtimeSync/functions.h @@ -9,7 +9,7 @@ class wxDirPickerCtrl; namespace RealtimeSync { - void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); +void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); } #endif // FUNCTIONS_H_INCLUDED diff --git a/RealtimeSync/guiGenerated.cpp b/RealtimeSync/guiGenerated.cpp index 7e705927..aa4a8261 100644 --- a/RealtimeSync/guiGenerated.cpp +++ b/RealtimeSync/guiGenerated.cpp @@ -13,7 +13,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) { - this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + this->SetSizeHints( wxSize( 420,440 ), wxDefaultSize ); m_menubar1 = new wxMenuBar( 0 ); m_menuFile = new wxMenu(); @@ -56,9 +56,35 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( 0, 10, 0, 0, 5 ); - m_staticText2 = new wxStaticText( m_panelMain, wxID_ANY, _("Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed."), wxDefaultPosition, wxDefaultSize, 0|wxDOUBLE_BORDER ); - m_staticText2->Wrap( 350 ); - bSizer1->Add( m_staticText2, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 40 ); + wxStaticBoxSizer* sbSizer41; + sbSizer41 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, wxEmptyString ), wxVERTICAL ); + + m_staticText2 = new wxStaticText( m_panelMain, wxID_ANY, _("Usage:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + m_staticText2->SetFont( wxFont( 10, 74, 90, 90, true, wxT("Tahoma") ) ); + + sbSizer41->Add( m_staticText2, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticText3 = new wxStaticText( m_panelMain, wxID_ANY, _("1. Select directories to monitor."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + sbSizer41->Add( m_staticText3, 0, wxLEFT, 10 ); + + m_staticText4 = new wxStaticText( m_panelMain, wxID_ANY, _("2. Enter a command line."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + sbSizer41->Add( m_staticText4, 0, wxLEFT, 10 ); + + m_staticText5 = new wxStaticText( m_panelMain, wxID_ANY, _("3. Press 'Start'."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + sbSizer41->Add( m_staticText5, 0, wxLEFT, 10 ); + + m_staticline3 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + sbSizer41->Add( m_staticline3, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + m_staticText21 = new wxStaticText( m_panelMain, wxID_ANY, _("The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText21->Wrap( -1 ); + sbSizer41->Add( m_staticText21, 0, wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + bSizer1->Add( sbSizer41, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 40 ); m_staticline2 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizer1->Add( m_staticline2, 0, wxTOP|wxBOTTOM|wxEXPAND, 10 ); @@ -119,7 +145,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( bSizer8, 1, wxEXPAND, 5 ); wxStaticBoxSizer* sbSizer3; - sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Commandline") ), wxVERTICAL ); + sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Command line") ), wxVERTICAL ); m_textCtrlCommand = new wxTextCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); sbSizer3->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM, 5 ); @@ -133,7 +159,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Delay") ), wxVERTICAL ); m_spinCtrlDelay = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 0, 2000000000, 0 ); - m_spinCtrlDelay->SetToolTip( _("Delay between detection of changes and execution of commandline in seconds") ); + m_spinCtrlDelay->SetToolTip( _("Delay between detection of changes and execution of command line in seconds") ); sbSizer4->Add( m_spinCtrlDelay, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); diff --git a/RealtimeSync/guiGenerated.h b/RealtimeSync/guiGenerated.h index 91669af8..7be541d4 100644 --- a/RealtimeSync/guiGenerated.h +++ b/RealtimeSync/guiGenerated.h @@ -23,14 +23,14 @@ class wxButtonWithImage; #include <wx/settings.h> #include <wx/stattext.h> #include <wx/statline.h> +#include <wx/sizer.h> +#include <wx/statbox.h> #include <wx/bmpbuttn.h> #include <wx/button.h> -#include <wx/sizer.h> #include <wx/textctrl.h> #include <wx/filepicker.h> #include <wx/panel.h> #include <wx/scrolwin.h> -#include <wx/statbox.h> #include <wx/spinctrl.h> #include <wx/frame.h> @@ -52,6 +52,11 @@ class MainDlgGenerated : public wxFrame wxPanel* m_panelMain; wxStaticText* m_staticText2; + wxStaticText* m_staticText3; + wxStaticText* m_staticText4; + wxStaticText* m_staticText5; + wxStaticLine* m_staticline3; + wxStaticText* m_staticText21; wxStaticLine* m_staticline2; wxPanel* m_panelMainFolder; wxBitmapButton* m_bpButtonAddFolder; diff --git a/RealtimeSync/mainDialog.cpp b/RealtimeSync/mainDialog.cpp index 8d9c7d7a..81af1ce0 100644 --- a/RealtimeSync/mainDialog.cpp +++ b/RealtimeSync/mainDialog.cpp @@ -2,7 +2,6 @@ #include "resources.h" #include "../shared/customButton.h" #include "../shared/standardPaths.h" -//#include "../shared/globalFunctions.h" #include <wx/msgdlg.h> #include <wx/wupdlock.h> #include "watcher.h" @@ -13,6 +12,8 @@ #include "xmlFreeFileSync.h" #include "../shared/systemConstants.h" #include "../shared/stringConv.h" +#include "../shared/staticAssert.h" +#include "../shared/buildInfo.h" using namespace FreeFileSync; @@ -20,17 +21,17 @@ using namespace FreeFileSync; MainDialog::MainDialog(wxDialog *dlg, const wxString& cfgFilename, wxHelpController& helpController) - : MainDlgGenerated(dlg), - helpController_(helpController) + : MainDlgGenerated(dlg), + helpController_(helpController) { wxWindowUpdateLocker dummy(this); //avoid display distortion m_bpButtonRemoveTopFolder->Hide(); m_panelMainFolder->Layout(); - m_bpButtonAddFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapAddFolderPair); - m_bpButtonRemoveTopFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); - m_buttonStart->setBitmapFront(*GlobalResources::getInstance().bitmapStart); + m_bpButtonAddFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); + m_bpButtonRemoveTopFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); + m_buttonStart->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("startRed"))); m_buttonStart->SetFocus(); //register key event @@ -126,11 +127,11 @@ const wxString& MainDialog::lastConfigFileName() void MainDialog::OnShowHelp(wxCommandEvent& event) { - #ifdef FFS_WIN +#ifdef FFS_WIN helpController_.DisplaySection(wxT("html\\advanced\\RealtimeSync.html")); - #elif defined FFS_LINUX +#elif defined FFS_LINUX helpController_.DisplaySection(wxT("html/advanced/RealtimeSync.html")); - #endif +#endif } @@ -139,11 +140,18 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event) //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode)"); + build += wxT(" - Unicode"); #else - build += wxT(" - ANSI)"); + build += wxT(" - ANSI"); #endif //wxUSE_UNICODE + //compile time info about 32/64-bit build + if (Utility::is64BitBuild) + build += wxT(" x64)"); + else + build += wxT(" x86)"); + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + wxMessageDialog* aboutDlg = new wxMessageDialog(this, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK); aboutDlg->ShowModal(); } @@ -356,7 +364,7 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron { //add new folder pair FolderPanel* newFolder = new FolderPanel(m_scrolledWinFolders); - newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); + newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); //get size of scrolled window folderHeight = newFolder->GetSize().GetHeight(); diff --git a/RealtimeSync/mainDialog.h b/RealtimeSync/mainDialog.h index 8447d269..8a5e87bf 100644 --- a/RealtimeSync/mainDialog.h +++ b/RealtimeSync/mainDialog.h @@ -16,7 +16,7 @@ namespace xmlAccess { - struct XmlRealConfig; +struct XmlRealConfig; } @@ -24,8 +24,8 @@ class FolderPanel : public FolderGenerated { public: FolderPanel(wxWindow* parent) : - FolderGenerated(parent), - dragDropOnFolder(new FreeFileSync::DragDropOnDlg(this, m_dirPicker, m_txtCtrlDirectory)) {} + FolderGenerated(parent), + dragDropOnFolder(new FreeFileSync::DragDropOnDlg(this, m_dirPicker, m_txtCtrlDirectory)) {} private: //support for drag and drop diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp index fe2a5ced..eeb89563 100644 --- a/RealtimeSync/resources.cpp +++ b/RealtimeSync/resources.cpp @@ -19,12 +19,7 @@ const GlobalResources& GlobalResources::getInstance() GlobalResources::GlobalResources() { - //map, allocate and initialize pictures - bitmapResource[wxT("start red.png")] = (bitmapStart = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("add pair.png")] = (bitmapAddFolderPair = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("remove pair.png")] = (bitmapRemoveFolderPair = new wxBitmap(wxNullBitmap)); - - programIcon = new wxIcon(wxNullIcon); + programIcon = new wxIcon(wxNullIcon); } @@ -49,7 +44,6 @@ void GlobalResources::load() const wxZipInputStream resourceFile(input); - std::map<wxString, wxBitmap*>::iterator bmp; while (true) { std::auto_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); @@ -58,24 +52,31 @@ void GlobalResources::load() const const wxString name = entry->GetName(); - //search if entry is available in map - if ((bmp = bitmapResource.find(name)) != bitmapResource.end()) - *(bmp->second) = wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + //generic image loading + if (name.EndsWith(wxT(".png"))) + { + if (bitmapResource.find(name) == bitmapResource.end()) //avoid duplicate entry: prevent memory leak! + bitmapResource[name] = new wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + } } } #ifdef FFS_WIN + //for compatibility it seems we need to stick with a "real" icon *programIcon = wxIcon(wxT("A_PROGRAM_ICON")); #else -#include "RealtimeSync.xpm" - *programIcon = wxIcon(RealtimeSync_xpm); + //use big logo bitmap for better quality + programIcon->CopyFromBitmap(getImageByName(wxT("RealtimeSync.png"))); #endif } const wxBitmap& GlobalResources::getImageByName(const wxString& imageName) const { - std::map<wxString, wxBitmap*>::const_iterator bmp = bitmapResource.find(imageName); + const std::map<wxString, wxBitmap*>::const_iterator bmp = imageName.Find(wxChar('.')) == wxNOT_FOUND ? //assume .png ending if nothing else specified + bitmapResource.find(imageName + wxT(".png")) : + bitmapResource.find(imageName); + if (bmp != bitmapResource.end()) return *bmp->second; else diff --git a/RealtimeSync/resources.h b/RealtimeSync/resources.h index 3a0cde7b..6a6cd976 100644 --- a/RealtimeSync/resources.h +++ b/RealtimeSync/resources.h @@ -14,10 +14,6 @@ public: const wxBitmap& getImageByName(const wxString& imageName) const; //image resource objects - wxBitmap* bitmapStart; - wxBitmap* bitmapAddFolderPair; - wxBitmap* bitmapRemoveFolderPair; - wxIcon* programIcon; void load() const; //loads bitmap resources on program startup: logical const! diff --git a/RealtimeSync/trayMenu.cpp b/RealtimeSync/trayMenu.cpp index 5d9d2430..01bcda48 100644 --- a/RealtimeSync/trayMenu.cpp +++ b/RealtimeSync/trayMenu.cpp @@ -10,6 +10,8 @@ #include <wx/timer.h> #include <wx/utils.h> #include <wx/log.h> +#include "../shared/staticAssert.h" +#include "../shared/buildInfo.h" class RtsTrayIcon; @@ -42,9 +44,9 @@ class RtsTrayIcon : public wxTaskBarIcon { public: RtsTrayIcon(WaitCallbackImpl* callback) : - m_callback(callback) + m_callback(callback) { - wxTaskBarIcon::SetIcon(*GlobalResources::getInstance().programIcon, wxT("RealtimeSync")); + wxTaskBarIcon::SetIcon(*GlobalResources::getInstance().programIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active...")); //register double-click Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIcon::resumeToMain), NULL, this); @@ -89,11 +91,18 @@ private: //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode)"); + build += wxT(" - Unicode"); #else - build += wxT(" - ANSI)"); + build += wxT(" - ANSI"); #endif //wxUSE_UNICODE + //compile time info about 32/64-bit build + if (Utility::is64BitBuild) + build += wxT(" x64)"); + else + build += wxT(" x86)"); + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + wxMessageDialog* aboutDlg = new wxMessageDialog(NULL, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK); aboutDlg->ShowModal(); aboutDlg->Destroy(); @@ -145,8 +154,8 @@ private: WaitCallbackImpl::WaitCallbackImpl() : - m_abortRequested(false), - m_resumeRequested(false) + m_abortRequested(false), + m_resumeRequested(false) { trayMenu.reset(new RtsTrayIcon(this)); } @@ -172,7 +181,7 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces WaitCallbackImpl callback; if (config.commandline.empty()) - throw FreeFileSync::FileError(_("Commandline is empty!")); + throw FreeFileSync::FileError(_("Command line is empty!")); long lastExec = 0; while (true) diff --git a/RealtimeSync/trayMenu.h b/RealtimeSync/trayMenu.h index 04b07f8a..99f2f90a 100644 --- a/RealtimeSync/trayMenu.h +++ b/RealtimeSync/trayMenu.h @@ -7,13 +7,13 @@ namespace RealtimeSync { - enum MonitorResponse - { - RESUME, - QUIT - }; +enum MonitorResponse +{ + RESUME, + QUIT +}; - MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config); +MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config); } diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 97471397..67dae521 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -5,9 +5,15 @@ #include <wx/filefn.h> #include "../shared/fileHandling.h" #include "../shared/stringConv.h" +#include <stdexcept> +#include <map> +#include <wx/timer.h> #ifdef FFS_WIN +//#include "../shared/fileId.h" +//#include "Dbt.h" #include <wx/msw/wrapwin.h> //includes "windows.h" +#include "../shared/longPathPrefix.h" #elif defined FFS_LINUX #include <wx/timer.h> @@ -20,6 +26,191 @@ using namespace FreeFileSync; #ifdef FFS_WIN +/* +template <class T> //have a disctinct static variable per class! +class InstanceCounter //exception safety!!!! use RAII for counter inc/dec! +{ +public: + InstanceCounter() + { + ++instanceCount; + //we're programming on global variables: only one instance of NotifyDeviceArrival allowed at a time! + if (instanceCount > 1) + throw std::logic_error("Only one instance of NotifyDeviceArrival allowed!"); + } + ~InstanceCounter() + { + --instanceCount; + } +private: + static size_t instanceCount; //this class needs to be a singleton but with variable lifetime! => count instances to check consistency +}; +template <class T> //we need a disctinct static variable per class! +size_t InstanceCounter<T>::instanceCount = 0; + + +std::set<Zstring> driveNamesArrived; //letters of newly arrived drive names + + +//convert bitmask into "real" drive-letter +void notifyDriveFromMask (ULONG unitmask) +{ + for (wchar_t i = 0; i < 26; ++i) + { + if (unitmask & 0x1) + { + Zstring newDrivePath; + newDrivePath += DefaultChar('A') + i; + newDrivePath += DefaultStr(":\\"); + driveNamesArrived.insert(newDrivePath); + return; + } + unitmask = unitmask >> 1; + } +} + + +LRESULT CALLBACK MainWndProc( + HWND hwnd, // handle to window + UINT uMsg, // message identifier + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + + //detect device arrival: http://msdn.microsoft.com/en-us/library/aa363215(VS.85).aspx + if (uMsg == WM_DEVICECHANGE) + { + if (wParam == DBT_DEVICEARRIVAL) + { + PDEV_BROADCAST_HDR lpdb = reinterpret_cast<PDEV_BROADCAST_HDR>(lParam); + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) + { + PDEV_BROADCAST_VOLUME lpdbv = reinterpret_cast<PDEV_BROADCAST_VOLUME>(lpdb); + //warning: lpdbv->dbcv_flags is 0 for USB-sticks! + + //insert drive name notification into global variable: + notifyDriveFromMask(lpdbv->dbcv_unitmask); + } + } + } + //default + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + + +class NotifyDeviceArrival //e.g. insertion of USB-Stick +{ +public: + NotifyDeviceArrival() : + parentInstance(NULL), + registeredClass(NULL), + windowHandle(NULL) + { + //get program's module handle + parentInstance = GetModuleHandle(NULL); + if (parentInstance == NULL) + throw FreeFileSync::FileError(wxString(("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted()+ wxT(" (GetModuleHandle)")); + + //register the main window class + WNDCLASS wc; + wc.style = 0; + wc.lpfnWndProc = MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = parentInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = wxT("DeviceArrivalWatcher"); + + registeredClass =:: RegisterClass(&wc); + if (registeredClass == 0) + throw FreeFileSync::FileError(wxString(("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted()+ wxT(" (RegisterClass)")); + + //create dummy-window + windowHandle = ::CreateWindow( + reinterpret_cast<LPCTSTR>(registeredClass), //LPCTSTR lpClassName OR ATOM in low-order word! + 0, //LPCTSTR lpWindowName, + 0, //DWORD dwStyle, + 0, //int x, + 0, //int y, + 0, //int nWidth, + 0, //int nHeight, + 0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)! + NULL, //HMENU hMenu, + parentInstance, //HINSTANCE hInstance, + NULL); //LPVOID lpParam + if (windowHandle == NULL) + throw FreeFileSync::FileError(wxString( ("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted() + wxT(" (CreateWindow)")); + + //clear global variable + driveNamesArrived.clear(); + } + + ~NotifyDeviceArrival() + { + //clean-up in reverse order + if (windowHandle != NULL) + ::DestroyWindow(windowHandle); + + if (registeredClass != 0) + ::UnregisterClass(reinterpret_cast<LPCTSTR>(registeredClass), //LPCTSTR lpClassName OR ATOM in low-order word! + parentInstance); //HINSTANCE hInstance + } + + + //test if one of the notifications matches one of the directory paths specified + bool notificationsFound(const std::vector<Zstring>& dirList) const + { + //do NOT rely on string parsing! use (volume directory) file ids! + std::set<Utility::FileID> notifiedIds; + for (std::set<Zstring>::const_iterator j = driveNamesArrived.begin(); j != driveNamesArrived.end(); ++j) + { + const Utility::FileID notifiedVolId = Utility::retrieveFileID(*j); + if (notifiedVolId != Utility::FileID()) + notifiedIds.insert(notifiedVolId); + } + //clear global variable + driveNamesArrived.clear(); + + if (!notifiedIds.empty()) //minor optimization + { + for (std::vector<Zstring>::const_iterator i = dirList.begin(); i != dirList.end(); ++i) + { + //retrieve volume name + wchar_t volumeNameRaw[1000]; + if (::GetVolumePathName(i->c_str(), //__in LPCTSTR lpszFileName, + volumeNameRaw, //__out LPTSTR lpszVolumePathName, + 1000)) //__in DWORD cchBufferLength + { + const Utility::FileID monitoredId = Utility::retrieveFileID(volumeNameRaw); + if (monitoredId != Utility::FileID()) + { + if (notifiedIds.find(monitoredId) != notifiedIds.end()) + return true; + } + } + } + } + + return false; + } + +private: + HINSTANCE parentInstance; + ATOM registeredClass; + HWND windowHandle; + + //we're programming on global variables: only one instance of NotifyDeviceArrival allowed at a time! + InstanceCounter<NotifyDeviceArrival> dummy; //exception safety!!!! use RAII for counter inc/dec! +}; +*/ + +//-------------------------------------------------------------------------------------------------------------- class ChangeNotifications { public: @@ -75,11 +266,53 @@ private: #endif +class NotifyDirectoryArrival //detect changes to directory availability +{ +public: + //initialization + void addForMonitoring(const Zstring& dirName, bool isExisting) //dir-existence already checked by calling method, avoid double-checking -> consistency! + { + availablility[dirName] = isExisting; + } + + //detection + bool changeDetected() //polling explicitly allowed! + { + const int UPDATE_INTERVAL = 1000; //1 second interval + + static wxLongLong lastExec = 0; + const wxLongLong newExec = wxGetLocalTimeMillis(); + + if (newExec - lastExec >= UPDATE_INTERVAL) + { + lastExec = newExec; + + for (std::map<Zstring, bool>::iterator i = availablility.begin(); i != availablility.end(); ++i) + if (FreeFileSync::dirExists(i->first) != i->second) //change in availability + { + if (i->second) //directory doesn't exist anymore: no reason to trigger the commandline! (sometimes triggered by ChangeNotifications anyway...) + i->second = false; //update value, so that dir-arrival will be detected next time + else //directory arrival: trigger commandline! + return true; + } + } + + return false; + } + +private: + std::map<Zstring, bool> availablility; //save avail. status for each directory +}; + + void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler) { if (dirNames.empty()) //pathological case, but check is needed later return; + //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks) + NotifyDirectoryArrival monitorAvailability; + #ifdef FFS_WIN ChangeNotifications notifications; @@ -88,47 +321,58 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(i->c_str()); if (formattedDir.empty()) - throw FreeFileSync::FileError(_("Please fill all empty directory fields.")); - else if (!FreeFileSync::dirExists(formattedDir)) - throw FreeFileSync::FileError(wxString(_("Directory does not exist:")) + wxT("\n") + - wxT("\"") + zToWx(formattedDir) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted()); - - const HANDLE rv = ::FindFirstChangeNotification( - formattedDir.c_str(), //__in LPCTSTR lpPathName, - true, //__in BOOL bWatchSubtree, - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE); //__in DWORD dwNotifyFilter - - if (rv == INVALID_HANDLE_VALUE) + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); + + const bool isExisting = FreeFileSync::dirExists(formattedDir); + if (isExisting) { - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + *i + wxT("\""); - throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + const HANDLE rv = ::FindFirstChangeNotification( + FreeFileSync::applyLongPathPrefix(formattedDir).c_str(), //__in LPCTSTR lpPathName, + true, //__in BOOL bWatchSubtree, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE); //__in DWORD dwNotifyFilter + + if (rv == INVALID_HANDLE_VALUE) + { + const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + *i + wxT("\""); + throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + } + + notifications.addHandle(rv); } + //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick - notifications.addHandle(rv); + monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant } while (true) { - const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context - notifications.getSize(), //__in DWORD nCount, - notifications.getArray(), //__in const HANDLE *lpHandles, - false, //__in BOOL bWaitAll, - UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds - if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) - return; //directory change detected - else if (rv == WAIT_FAILED) - throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); - else if (rv == WAIT_TIMEOUT) - statusHandler->requestUiRefresh(); + //check for changes within directories: + if (notifications.getSize() > 0) + { + const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context + notifications.getSize(), //__in DWORD nCount, + notifications.getArray(), //__in const HANDLE *lpHandles, + false, //__in BOOL bWaitAll, + UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds + if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) + return; //directory change detected + else if (rv == WAIT_FAILED) + throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + //else if (rv == WAIT_TIMEOUT) + } + + if (monitorAvailability.changeDetected()) //check for newly arrived devices: + return; + + statusHandler->requestUiRefresh(); } #elif defined FFS_LINUX - std::vector<std::string> fullDirList; + std::vector<std::string> fullDirList; //including subdirectories! //add all subdirectories for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) @@ -136,17 +380,19 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(wxToZ(*i)); if (formattedDir.empty()) - throw FreeFileSync::FileError(_("Please fill all empty directory fields.")); + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); - else if (!FreeFileSync::dirExists(formattedDir)) - throw FreeFileSync::FileError(wxString(_("Directory does not exist:")) + wxT("\n") + - wxT("\"") + zToWx(formattedDir) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted()); + const bool isExisting = FreeFileSync::dirExists(formattedDir); + if (isExisting) + { + fullDirList.push_back(formattedDir.c_str()); + //get all subdirectories + DirsOnlyTraverser traverser(fullDirList); + FreeFileSync::traverseFolder(formattedDir, false, &traverser); //don't traverse into symlinks (analog to windows build) + } + //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick - fullDirList.push_back(formattedDir.c_str()); - //get all subdirectories - DirsOnlyTraverser traverser(fullDirList); - FreeFileSync::traverseFolder(formattedDir, false, &traverser); //don't traverse into symlinks (analog to windows build) + monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant } try @@ -178,6 +424,7 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal } } + while (true) { notifications.WaitForEvents(); //called in non-blocking mode @@ -185,6 +432,9 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal if (notifications.GetEventCount() > 0) return; //directory change detected + if (monitorAvailability.changeDetected()) //check for newly arrived devices: + return; + wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL); statusHandler->requestUiRefresh(); } @@ -199,3 +449,10 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal } #endif } + + + + + + + diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h index 1655eebf..2f3990c2 100644 --- a/RealtimeSync/watcher.h +++ b/RealtimeSync/watcher.h @@ -8,16 +8,16 @@ namespace RealtimeSync { - const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss +const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss - class WaitCallback - { - public: - virtual ~WaitCallback() {} - virtual void requestUiRefresh() = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() - }; +class WaitCallback +{ +public: + virtual ~WaitCallback() {} + virtual void requestUiRefresh() = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() +}; - void waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler); //throw(FreeFileSync::FileError); +void waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler); //throw(FreeFileSync::FileError); } #endif // WATCHER_H_INCLUDED diff --git a/RealtimeSync/xmlFreeFileSync.h b/RealtimeSync/xmlFreeFileSync.h index 8de9af08..55687d93 100644 --- a/RealtimeSync/xmlFreeFileSync.h +++ b/RealtimeSync/xmlFreeFileSync.h @@ -8,9 +8,9 @@ namespace RealtimeSync { - void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::XmlError); +void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::XmlError); - int getProgramLanguage(); +int getProgramLanguage(); } #endif // XMLFREEFILESYNC_H_INCLUDED diff --git a/RealtimeSync/xmlProcessing.h b/RealtimeSync/xmlProcessing.h index 90842abf..b8207973 100644 --- a/RealtimeSync/xmlProcessing.h +++ b/RealtimeSync/xmlProcessing.h @@ -8,16 +8,16 @@ namespace xmlAccess { - struct XmlRealConfig - { - XmlRealConfig() : delay(5) {} - std::vector<wxString> directories; - wxString commandline; - unsigned int delay; - }; +struct XmlRealConfig +{ + XmlRealConfig() : delay(5) {} + std::vector<wxString> directories; + wxString commandline; + unsigned int delay; +}; - void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError); - void writeRealConfig(const XmlRealConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); +void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError); +void writeRealConfig(const XmlRealConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); } #endif // XMLPROCESSING_H_INCLUDED diff --git a/algorithm.cpp b/algorithm.cpp index 566bae27..0940674d 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -10,7 +10,7 @@ #include "shared/stringConv.h" #include "shared/globalFunctions.h" #include "shared/loki/TypeManip.h" -#include "shared/loki/NullType.h" +//#include "shared/loki/NullType.h" using namespace FreeFileSync; @@ -135,180 +135,149 @@ bool FreeFileSync::allElementsEqual(const FolderComparison& folderCmp) } //--------------------------------------------------------------------------------------------------------------- -enum Answer +inline +bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned int tolerance) { - CHANGE_DETECTED, - NO_CHANGE, - CANT_SAY_FILTERING_CHANGED -}; - + if (a < b) + return b - a <= tolerance; + else + return a - b <= tolerance; +} +//--------------------------------------------------------------------------------------------------------------- -template <bool respectFiltering> -class DetectChanges +class DataSetFile { public: - DetectChanges(const DirContainer* dirCont, //DirContainer in sense of a HierarchyObject - const FilterProcess::FilterRef& dbFilter); - - DetectChanges(const DirContainer* dirCont); //DirContainer in sense of a HierarchyObject - - template <SelectedSide side> - Answer detectFileChange(const FileMapping& fileObj) const; - - struct DirAnswer + DataSetFile(const FileMapping& fileObj, Loki::Int2Type<LEFT_SIDE>) : + lastWriteTime_(NULL), + fileSize_(NULL) { - DirAnswer(Answer status, const DetectChanges instance) : dirStatus(status), subDirInstance(instance) {} - Answer dirStatus; - DetectChanges subDirInstance; //not valid if dirStatus == CANT_SAY_FILTERING_CHANGED - }; - template <SelectedSide side> - DirAnswer detectDirChange(const DirMapping& dirObj) const; - -private: - const DirContainer* const dirCont_; //if NULL: did not exist during db creation - typename Loki::Select<respectFiltering, const FilterProcess::FilterRef, Loki::NullType>::Result dbFilter_; //filter setting that was used when db was created -}; - - -template <> -inline -DetectChanges<true>::DetectChanges(const DirContainer* dirCont, //DirContainer in sense of a HierarchyObject - const FilterProcess::FilterRef& dbFilter) : - dirCont_(dirCont), - dbFilter_(dbFilter) {} - - -template <> -inline -DetectChanges<false>::DetectChanges(const DirContainer* dirCont) : //DirContainer in sense of a HierarchyObject - dirCont_(dirCont) {} + if (!fileObj.isEmpty<LEFT_SIDE>()) + { + lastWriteTime_ = &fileObj.getLastWriteTime<LEFT_SIDE>(); + fileSize_ = &fileObj.getFileSize<LEFT_SIDE>(); + } + } + DataSetFile(const FileMapping& fileObj, Loki::Int2Type<RIGHT_SIDE>) : + lastWriteTime_(NULL), + fileSize_(NULL) + { + if (!fileObj.isEmpty<RIGHT_SIDE>()) + { + lastWriteTime_ = &fileObj.getLastWriteTime<RIGHT_SIDE>(); + fileSize_ = &fileObj.getFileSize<RIGHT_SIDE>(); + } + } -template <SelectedSide side> -Answer detectFileChangeSub(const FileMapping& fileObj, const DirContainer* dbDirectory) -{ - if (dbDirectory) + DataSetFile(const FileContainer* fileCont) : + lastWriteTime_(NULL), + fileSize_(NULL) { - DirContainer::SubFileList::const_iterator j = dbDirectory->getSubFiles().find(fileObj.getObjShortName()); - if (j == dbDirectory->getSubFiles().end()) + if (fileCont) { - if (fileObj.isEmpty<side>()) - return NO_CHANGE; - else - return CHANGE_DETECTED; //->create + const FileDescriptor& dbData = fileCont->getData(); + lastWriteTime_ = &dbData.lastWriteTimeRaw; + fileSize_ = &dbData.fileSize; } + } + + bool operator==(const DataSetFile& other) const + { + if (lastWriteTime_ == NULL) + return other.lastWriteTime_ == NULL; else { - if (fileObj.isEmpty<side>()) - return CHANGE_DETECTED; //->delete + if (other.lastWriteTime_ == NULL) + return false; else { - const FileDescriptor& dbData = j->second.getData(); - if ( fileObj.getLastWriteTime<side>() == dbData.lastWriteTimeRaw && - fileObj.getFileSize<side>() == dbData.fileSize) - return NO_CHANGE; - else - return CHANGE_DETECTED; //->update + //respect 2 second FAT/FAT32 precision! copying a file to a FAT32 drive changes it's modification date by up to 2 seconds + return ::sameFileTime(*lastWriteTime_, *other.lastWriteTime_, 2) && + *fileSize_ == *other.fileSize_; } } } - else + + template <class T> + bool operator!=(const T& other) const { - if (fileObj.isEmpty<side>()) - return NO_CHANGE; - else - return CHANGE_DETECTED; //->create + return !(*this == other); } -} - -template <> -template <SelectedSide side> -inline -Answer DetectChanges<false>::detectFileChange(const FileMapping& fileObj) const -{ - return detectFileChangeSub<side>(fileObj, dirCont_); -} +private: + const wxLongLong* lastWriteTime_; //optional + const wxULongLong* fileSize_; //optional +}; -template <> -template <SelectedSide side> -inline -Answer DetectChanges<true>::detectFileChange(const FileMapping& fileObj) const +//----------------------------------- +class DataSetDir { - //if filtering would have excluded file during database creation, then we can't say anything about its former state - if (!dbFilter_->passFileFilter(fileObj.getObjShortName())) - return CANT_SAY_FILTERING_CHANGED; +public: + DataSetDir(const DirMapping& dirObj, Loki::Int2Type<LEFT_SIDE>) : + existing(!dirObj.isEmpty<LEFT_SIDE>()) {} - return detectFileChangeSub<side>(fileObj, dirCont_); -} + DataSetDir(const DirMapping& dirObj, Loki::Int2Type<RIGHT_SIDE>) : + existing(!dirObj.isEmpty<RIGHT_SIDE>()) {} + DataSetDir(bool isExising) : + existing(isExising) {} -template <SelectedSide side> -Answer detectDirChangeSub(const DirMapping& dirObj, const DirContainer* dbDirectory, const DirContainer*& dbSubDirectory) -{ - if (dbDirectory) + bool operator==(const DataSetDir& other) const { - DirContainer::SubDirList::const_iterator j = dbDirectory->getSubDirs().find(dirObj.getObjShortName()); - if (j == dbDirectory->getSubDirs().end()) - { - if (dirObj.isEmpty<side>()) - return NO_CHANGE; - else - return CHANGE_DETECTED; //->create - } - else - { - dbSubDirectory = &j->second; - if (dirObj.isEmpty<side>()) - return CHANGE_DETECTED; //->delete - else - return NO_CHANGE; - } + return existing == other.existing; } - else + + template <class T> + bool operator!=(const T& other) const { - if (dirObj.isEmpty<side>()) - return NO_CHANGE; - else - return CHANGE_DETECTED; //->create + return !(*this == other); } -} +private: + bool existing; +}; -template <> -template <SelectedSide side> -DetectChanges<false>::DirAnswer DetectChanges<false>::detectDirChange(const DirMapping& dirObj) const + +//-------------------------------------------------------------------------------------------------------- +DataSetFile retrieveDataSetFile(const Zstring& objShortName, const DirContainer* dbDirectory) { - const DirContainer* dbSubDir = NULL; - const Answer answer = detectDirChangeSub<side>(dirObj, dirCont_, dbSubDir); + if (dbDirectory) + { + const DirContainer::SubFileList& fileList = dbDirectory->getSubFiles(); + const DirContainer::SubFileList::const_iterator j = fileList.find(objShortName); + if (j != fileList.end()) + return DataSetFile(&j->second); + } - return DirAnswer(answer, DetectChanges<false>(dbSubDir)); + //object not found + return DataSetFile(NULL); } -template <> -template <SelectedSide side> -DetectChanges<true>::DirAnswer DetectChanges<true>::detectDirChange(const DirMapping& dirObj) const +std::pair<DataSetDir, const DirContainer*> retrieveDataSetDir(const Zstring& objShortName, const DirContainer* dbDirectory) { - //if filtering would have excluded file during database creation, then we can't say anything about its former state - if (!dbFilter_->passDirFilter(dirObj.getObjShortName(), NULL)) - return DirAnswer(CANT_SAY_FILTERING_CHANGED, DetectChanges<true>(NULL, dbFilter_)); - - const DirContainer* dbSubDir = NULL; - const Answer answer = detectDirChangeSub<side>(dirObj, dirCont_, dbSubDir); + if (dbDirectory) + { + const DirContainer::SubDirList& dirList = dbDirectory->getSubDirs(); + const DirContainer::SubDirList::const_iterator j = dirList.find(objShortName); + if (j != dirList.end()) + return std::make_pair(DataSetDir(true), &j->second); + } - return DirAnswer(answer, DetectChanges<true>(dbSubDir, dbFilter_)); + //object not found + return std::make_pair(DataSetDir(false), static_cast<const DirContainer*>(NULL)); } -//---------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------------- class SetDirChangedFilter { public: SetDirChangedFilter() : - txtFilterChanged(_("Cannot determine sync-direction: Changed filter settings!")) {} + txtFilterChanged(wxString(_("Cannot determine sync-direction:")) + wxT(" \n") + _("Filter settings have changed!")) {} void execute(HierarchyObject& hierObj) const { @@ -361,8 +330,11 @@ public: RedetermineAuto(BaseDirMapping& baseDirectory, DeterminationProblem* handler) : txtBothSidesChanged(_("Both sides have changed since last synchronization!")), - txtNoSideChanged(_("Cannot determine sync-direction: No change since last synchronization!")), - txtFilterChanged(_("Cannot determine sync-direction: Changed filter settings!")), + txtNoSideChanged(wxString(_("Cannot determine sync-direction:")) + wxT(" \n") + _("No change since last synchronization!")), + txtFilterChanged(wxString(_("Cannot determine sync-direction:")) + wxT(" \n") + _("Filter settings have changed!")), + txtLastSyncFail(wxString(_("Cannot determine sync-direction:")) + wxT(" \n") + _("Last synchronization not completed!")), + dbFilterLeft(NULL), + dbFilterRight(NULL), handler_(handler) { if (AllElementsEqual()(baseDirectory)) //nothing to do: abort and don't show any nag-screens @@ -383,33 +355,16 @@ public: const DirInformation& dirInfoLeft = *dirInfo.first; const DirInformation& dirInfoRight = *dirInfo.second; - if ( respectFiltering(baseDirectory, dirInfoLeft) && - respectFiltering(baseDirectory, dirInfoRight)) - { - execute(baseDirectory, - DetectChanges<true>(&dirInfoLeft.baseDirContainer, dirInfoLeft.filter), - DetectChanges<true>(&dirInfoRight.baseDirContainer, dirInfoRight.filter)); - } - else if ( !respectFiltering(baseDirectory, dirInfoLeft) && - respectFiltering( baseDirectory, dirInfoRight)) - { - execute(baseDirectory, - DetectChanges<false>(&dirInfoLeft.baseDirContainer), - DetectChanges<true>( &dirInfoRight.baseDirContainer, dirInfoRight.filter)); - } - else if ( respectFiltering( baseDirectory, dirInfoLeft) && - !respectFiltering(baseDirectory, dirInfoRight)) - { - execute(baseDirectory, - DetectChanges<true>( &dirInfoLeft.baseDirContainer, dirInfoLeft.filter), - DetectChanges<false>(&dirInfoRight.baseDirContainer)); - } - else - { - execute(baseDirectory, - DetectChanges<false>(&dirInfoLeft.baseDirContainer), - DetectChanges<false>(&dirInfoRight.baseDirContainer)); - } + //save db filter (if it needs to be considered only): + if (respectFiltering(baseDirectory, dirInfoLeft)) + dbFilterLeft = dirInfoLeft.filter.get(); + + if (respectFiltering(baseDirectory, dirInfoRight)) + dbFilterRight = dirInfoRight.filter.get(); + + execute(baseDirectory, + &dirInfoLeft.baseDirContainer, + &dirInfoRight.baseDirContainer); } @@ -422,6 +377,7 @@ private: return !dirInfo.filter->isNull() && *dirInfo.filter != *baseDirectory.getFilter(); } + std::pair<DirInfoPtr, DirInfoPtr> loadDBFile(const BaseDirMapping& baseDirectory) //return NULL on failure { try @@ -436,36 +392,49 @@ private: return std::pair<DirInfoPtr, DirInfoPtr>(); //NULL } + + bool filterConflictFound(const FileMapping& fileObj) const + { + //if filtering would have excluded file during database creation, then we can't say anything about its former state + return (dbFilterLeft && !dbFilterLeft ->passFileFilter(fileObj.getObjShortName())) || + (dbFilterRight && !dbFilterRight->passFileFilter(fileObj.getObjShortName())); + } + + + bool filterConflictFound(const DirMapping& dirObj) const + { + //if filtering would have excluded directory during database creation, then we can't say anything about its former state + return (dbFilterLeft && !dbFilterLeft ->passDirFilter(dirObj.getObjShortName(), NULL)) || + (dbFilterRight && !dbFilterRight->passDirFilter(dirObj.getObjShortName(), NULL)); + } + + template<typename Iterator, typename Function> friend Function std::for_each(Iterator, Iterator, Function); - template <bool dbLeftFilterActive, bool dbRightFilterActive> + void execute(HierarchyObject& hierObj, - const DetectChanges<dbLeftFilterActive>& dbLeft, - const DetectChanges<dbRightFilterActive>& dbRight) + const DirContainer* dbDirectoryLeft, + const DirContainer* dbDirectoryRight) { //process files std::for_each(hierObj.subFiles.begin(), hierObj.subFiles.end(), - boost::bind(&RedetermineAuto::processFile<dbLeftFilterActive, dbRightFilterActive>, this, _1, boost::ref(dbLeft), boost::ref(dbRight))); + boost::bind(&RedetermineAuto::processFile, this, _1, dbDirectoryLeft, dbDirectoryRight)); //process directories std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), - boost::bind(&RedetermineAuto::processDir<dbLeftFilterActive, dbRightFilterActive>, this, _1, boost::ref(dbLeft), boost::ref(dbRight))); + boost::bind(&RedetermineAuto::processDir, this, _1, dbDirectoryLeft, dbDirectoryRight)); } - template <bool dbLeftFilterActive, bool dbRightFilterActive> + void processFile(FileMapping& fileObj, - const DetectChanges<dbLeftFilterActive>& dbLeft, - const DetectChanges<dbRightFilterActive>& dbRight) + const DirContainer* dbDirectoryLeft, + const DirContainer* dbDirectoryRight) { const CompareFilesResult cat = fileObj.getCategory(); if (cat == FILE_EQUAL) return; - const Answer statusLeft = dbLeft. template detectFileChange<LEFT_SIDE>(fileObj); - const Answer statusRight = dbRight.template detectFileChange<RIGHT_SIDE>(fileObj); - - if ( statusLeft == CANT_SAY_FILTERING_CHANGED || - statusRight == CANT_SAY_FILTERING_CHANGED) + if (filterConflictFound(fileObj)) { if (cat == FILE_LEFT_SIDE_ONLY) fileObj.setSyncDir(SYNC_DIR_RIGHT); @@ -476,96 +445,155 @@ private: return; } + //determine datasets for change detection + const DataSetFile dataDbLeft = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryLeft); + const DataSetFile dataDbRight = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryRight); - if ( statusLeft == CHANGE_DETECTED && - statusRight == NO_CHANGE) - fileObj.setSyncDir(SYNC_DIR_RIGHT); - - else if ( statusLeft == NO_CHANGE && - statusRight == CHANGE_DETECTED) - fileObj.setSyncDir(SYNC_DIR_LEFT); + const DataSetFile dataCurrentLeft( fileObj, Loki::Int2Type<LEFT_SIDE>()); + const DataSetFile dataCurrentRight(fileObj, Loki::Int2Type<RIGHT_SIDE>()); - else if ( statusLeft == CHANGE_DETECTED && - statusRight == CHANGE_DETECTED) - fileObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + //evaluation + const bool changeOnLeft = dataDbLeft != dataCurrentLeft; + const bool changeOnRight = dataDbRight != dataCurrentRight; - else if ( statusLeft == NO_CHANGE && - statusRight == NO_CHANGE) + if (dataDbLeft == dataDbRight) //last sync seems to have been successful { - if (cat == FILE_LEFT_SIDE_ONLY) - fileObj.setSyncDir(SYNC_DIR_RIGHT); - else if (cat == FILE_RIGHT_SIDE_ONLY) - fileObj.setSyncDir(SYNC_DIR_LEFT); + if (changeOnLeft) + { + if (changeOnRight) + fileObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + else + fileObj.setSyncDir(SYNC_DIR_RIGHT); + } else - fileObj.setSyncDirConflict(txtNoSideChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + { + if (changeOnRight) + fileObj.setSyncDir(SYNC_DIR_LEFT); + else + { + if (cat == FILE_LEFT_SIDE_ONLY) + fileObj.setSyncDir(SYNC_DIR_RIGHT); + else if (cat == FILE_RIGHT_SIDE_ONLY) + fileObj.setSyncDir(SYNC_DIR_LEFT); + else + fileObj.setSyncDirConflict(txtNoSideChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + } + } + } + else //object did not complete last sync + { + if (changeOnLeft && changeOnRight) + fileObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + else + { + if (cat == FILE_LEFT_SIDE_ONLY) + fileObj.setSyncDir(SYNC_DIR_RIGHT); + else if (cat == FILE_RIGHT_SIDE_ONLY) + fileObj.setSyncDir(SYNC_DIR_LEFT); + else + fileObj.setSyncDirConflict(txtLastSyncFail); //set syncDir = SYNC_DIR_INT_CONFLICT + } } } - template <bool dbLeftFilterActive, bool dbRightFilterActive> void processDir(DirMapping& dirObj, - const DetectChanges<dbLeftFilterActive>& dbLeft, - const DetectChanges<dbRightFilterActive>& dbRight) + const DirContainer* dbDirectoryLeft, + const DirContainer* dbDirectoryRight) { - const typename DetectChanges<dbLeftFilterActive> ::DirAnswer statusLeft = dbLeft. template detectDirChange<LEFT_SIDE>(dirObj); - const typename DetectChanges<dbRightFilterActive>::DirAnswer statusRight = dbRight.template detectDirChange<RIGHT_SIDE>(dirObj); - const CompareDirResult cat = dirObj.getDirCategory(); - if (cat != DIR_EQUAL) + + if (filterConflictFound(dirObj)) { - if ( (statusLeft.dirStatus == CANT_SAY_FILTERING_CHANGED || - statusRight.dirStatus == CANT_SAY_FILTERING_CHANGED)) + switch (cat) { - switch (cat) - { - case DIR_LEFT_SIDE_ONLY: - dirObj.setSyncDir(SYNC_DIR_RIGHT); - break; - case DIR_RIGHT_SIDE_ONLY: - dirObj.setSyncDir(SYNC_DIR_LEFT); - break; - case DIR_EQUAL: - assert(false); - } - - SetDirChangedFilter().execute(dirObj); //filter issue for this directory => treat subfiles/-dirs the same - return; - } - else if ( statusLeft.dirStatus == CHANGE_DETECTED && - statusRight.dirStatus == NO_CHANGE) + case DIR_LEFT_SIDE_ONLY: dirObj.setSyncDir(SYNC_DIR_RIGHT); - - else if ( statusLeft.dirStatus == NO_CHANGE && - statusRight.dirStatus == CHANGE_DETECTED) + break; + case DIR_RIGHT_SIDE_ONLY: dirObj.setSyncDir(SYNC_DIR_LEFT); + break; + case DIR_EQUAL: + assert(false); + } - else if ( statusLeft.dirStatus == CHANGE_DETECTED && - statusRight.dirStatus == CHANGE_DETECTED) - dirObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + SetDirChangedFilter().execute(dirObj); //filter issue for this directory => treat subfiles/-dirs the same + return; + } + + //determine datasets for change detection + const std::pair<DataSetDir, const DirContainer*> dataDbLeftStuff = retrieveDataSetDir(dirObj.getObjShortName(), dbDirectoryLeft); + const std::pair<DataSetDir, const DirContainer*> dataDbRightStuff = retrieveDataSetDir(dirObj.getObjShortName(), dbDirectoryRight); + + const DataSetDir dataCurrentLeft( dirObj, Loki::Int2Type<LEFT_SIDE>()); + const DataSetDir dataCurrentRight(dirObj, Loki::Int2Type<RIGHT_SIDE>()); - else if ( statusLeft.dirStatus == NO_CHANGE && - statusRight.dirStatus == NO_CHANGE) + //evaluation + const bool changeOnLeft = dataDbLeftStuff.first != dataCurrentLeft; + const bool changeOnRight = dataDbRightStuff.first != dataCurrentRight; + + if (cat != DIR_EQUAL) + { + if (dataDbLeftStuff.first == dataDbRightStuff.first) //last sync seems to have been successful { - switch (cat) + if (changeOnLeft) { - case DIR_LEFT_SIDE_ONLY: - dirObj.setSyncDir(SYNC_DIR_RIGHT); - break; - case DIR_RIGHT_SIDE_ONLY: - dirObj.setSyncDir(SYNC_DIR_LEFT); - break; - case DIR_EQUAL: - assert(false); + if (changeOnRight) + dirObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + else + dirObj.setSyncDir(SYNC_DIR_RIGHT); + } + else + { + if (changeOnRight) + dirObj.setSyncDir(SYNC_DIR_LEFT); + else + { + switch (cat) + { + case DIR_LEFT_SIDE_ONLY: + dirObj.setSyncDir(SYNC_DIR_RIGHT); + break; + case DIR_RIGHT_SIDE_ONLY: + dirObj.setSyncDir(SYNC_DIR_LEFT); + break; + case DIR_EQUAL: + assert(false); + } + } + } + } + else //object did not complete last sync + { + if (changeOnLeft && changeOnRight) + dirObj.setSyncDirConflict(txtBothSidesChanged); //set syncDir = SYNC_DIR_INT_CONFLICT + else + { + switch (cat) + { + case DIR_LEFT_SIDE_ONLY: + dirObj.setSyncDir(SYNC_DIR_RIGHT); + break; + case DIR_RIGHT_SIDE_ONLY: + dirObj.setSyncDir(SYNC_DIR_LEFT); + break; + case DIR_EQUAL: + assert(false); + } } } } - execute(dirObj, statusLeft.subDirInstance, statusRight.subDirInstance); //recursion + execute(dirObj, dataDbLeftStuff.second, dataDbRightStuff.second); //recursion } const wxString txtBothSidesChanged; const wxString txtNoSideChanged; const wxString txtFilterChanged; + const wxString txtLastSyncFail; + + const BaseFilter* dbFilterLeft; //optional + const BaseFilter* dbFilterRight; //optional DeterminationProblem* const handler_; }; @@ -624,12 +652,14 @@ private: void operator()(FileMapping& fileObj) const { - fileObj.setSyncDir(newDirection_); + if (fileObj.getCategory() != FILE_EQUAL) + fileObj.setSyncDir(newDirection_); } void operator()(DirMapping& dirObj) const { - dirObj.setSyncDir(newDirection_); + if (dirObj.getDirCategory() != DIR_EQUAL) + dirObj.setSyncDir(newDirection_); execute(dirObj); //recursion } @@ -639,7 +669,8 @@ private: void FreeFileSync::setSyncDirectionRec(SyncDirection newDirection, FileSystemObject& fsObj) { - fsObj.setSyncDir(newDirection); + if (fsObj.getCategory() != FILE_EQUAL) + fsObj.setSyncDir(newDirection); DirMapping* dirObj = dynamic_cast<DirMapping*>(&fsObj); if (dirObj) //process subdirectories also! @@ -708,7 +739,7 @@ void FreeFileSync::setActiveStatus(bool newStatus, FreeFileSync::FileSystemObjec class FilterData { public: - FilterData(const FilterProcess& filterProcIn) : filterProc(filterProcIn) {} + FilterData(const BaseFilter& filterProcIn) : filterProc(filterProcIn) {} void execute(FreeFileSync::HierarchyObject& hierObj) { @@ -740,11 +771,11 @@ private: InOrExcludeAllRows<false>().execute(dirObj); //exclude all files dirs in subfolders } - const FilterProcess& filterProc; + const BaseFilter& filterProc; }; -void FreeFileSync::applyFiltering(const FilterProcess& filter, FreeFileSync::BaseDirMapping& baseDirectory) +void FreeFileSync::applyFiltering(const BaseFilter& filter, FreeFileSync::BaseDirMapping& baseDirectory) { FilterData(filter).execute(baseDirectory); } @@ -766,14 +797,14 @@ void FreeFileSync::applyFiltering(const MainConfiguration& currentMainCfg, Folde currentMainCfg.additionalPairs.end()); - const FilterProcess::FilterRef globalFilter(new NameFilter(currentMainCfg.includeFilter, currentMainCfg.excludeFilter)); + const BaseFilter::FilterRef globalFilter(new NameFilter(currentMainCfg.includeFilter, currentMainCfg.excludeFilter)); for (std::vector<FolderPairEnh>::const_iterator i = allPairs.begin(); i != allPairs.end(); ++i) { BaseDirMapping& baseDirectory = folderCmp[i - allPairs.begin()]; applyFiltering(*combineFilters(globalFilter, - FilterProcess::FilterRef(new NameFilter( + BaseFilter::FilterRef(new NameFilter( i->localFilter.includeFilter, i->localFilter.excludeFilter))), baseDirectory); @@ -916,7 +947,7 @@ private: }; -void FreeFileSync::deleteFromGridAndHD(FolderComparison& folderCmp, //attention: rows will be physically deleted! +void FreeFileSync::deleteFromGridAndHD(FolderComparison& folderCmp, //attention: rows will be physically deleted! std::vector<FileSystemObject*>& rowsToDeleteOnLeft, //refresh GUI grid after deletion to remove invalid rows std::vector<FileSystemObject*>& rowsToDeleteOnRight, //all pointers need to be bound! const bool deleteOnBothSides, @@ -1116,3 +1147,12 @@ void FreeFileSync::checkForDSTChange(const FileCompareResult& gridData, */ + + + + + + + + + diff --git a/algorithm.h b/algorithm.h index 580ad2dd..dbe5dd35 100644 --- a/algorithm.h +++ b/algorithm.h @@ -6,7 +6,7 @@ namespace FreeFileSync { -class FilterProcess; +class BaseFilter; void swapGrids(const MainConfiguration& config, FolderComparison& folderCmp); @@ -24,7 +24,7 @@ bool allElementsEqual(const FolderComparison& folderCmp); //filtering void applyFiltering(const MainConfiguration& currentMainCfg, FolderComparison& folderCmp); -void applyFiltering(const FilterProcess& filter, BaseDirMapping& baseDirectory); +void applyFiltering(const BaseFilter& filter, BaseDirMapping& baseDirectory); void setActiveStatus(bool newStatus, FolderComparison& folderCmp); //activate or deactivate all rows void setActiveStatus(bool newStatus, FileSystemObject& fsObj); //activate or deactivate row: works recursively! diff --git a/comparison.cpp b/comparison.cpp index 79105801..120a96c3 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -21,6 +21,10 @@ #include <boost/bind.hpp> #include <boost/scoped_array.hpp> +#ifdef FFS_WIN +#include "shared/longPathPrefix.h" +#endif + using namespace FreeFileSync; @@ -33,7 +37,7 @@ std::vector<FreeFileSync::FolderPairCfg> FreeFileSync::extractCompareCfg(const M mainCfg.additionalPairs.begin(), //add additional pairs mainCfg.additionalPairs.end()); - const FilterProcess::FilterRef globalFilter(new NameFilter(mainCfg.includeFilter, mainCfg.excludeFilter)); + const BaseFilter::FilterRef globalFilter(new NameFilter(mainCfg.includeFilter, mainCfg.excludeFilter)); std::vector<FolderPairCfg> output; for (std::vector<FolderPairEnh>::const_iterator i = allPairs.begin(); i != allPairs.end(); ++i) @@ -43,11 +47,11 @@ std::vector<FreeFileSync::FolderPairCfg> FreeFileSync::extractCompareCfg(const M mainCfg.filterIsActive ? combineFilters(globalFilter, - FilterProcess::FilterRef( + BaseFilter::FilterRef( new NameFilter( i->localFilter.includeFilter, i->localFilter.excludeFilter))) : - FilterProcess::FilterRef(new NullFilter), + BaseFilter::FilterRef(new NullFilter), i->altSyncConfig.get() ? i->altSyncConfig->syncConfiguration : mainCfg.syncConfiguration)); @@ -89,9 +93,13 @@ class BaseDirCallback : public DirCallback { friend class DirCallback; public: - BaseDirCallback(DirContainer& output, const FilterProcess::FilterRef& filter, StatusHandler* handler) : + BaseDirCallback(DirContainer& output, + const BaseFilter::FilterRef& filter, + unsigned int detectRenameThreshold, + StatusHandler* handler) : DirCallback(this, Zstring(), output, handler), textScanning(wxToZ(wxString(_("Scanning:")) + wxT(" \n"))), + detectRenameThreshold_(detectRenameThreshold), filterInstance(filter) {} virtual TraverseCallback::ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details); @@ -102,7 +110,8 @@ private: const Zstring textScanning; std::vector<CallbackPointer> callBackBox; //collection of callback pointers to handle ownership - const FilterProcess::FilterRef filterInstance; //always bound! + const unsigned int detectRenameThreshold_; + const BaseFilter::FilterRef filterInstance; //always bound! }; @@ -126,6 +135,16 @@ TraverseCallback::ReturnValue DirCallback::onFile(const DefaultChar* shortName, return TRAVERSING_CONTINUE; } + //warning: for windows retrieveFileID is slow as hell! approximately 3 * 10^-4 s per file! + //therefore only large files (that take advantage of detection of renaming when synchronizing) should be evaluated! + //testcase: scanning only files larger than 1 MB results in performance loss of 6% + +//#warning this call is NOT acceptable for Linux! +// //Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!) +// const Utility::FileID fileIdentifier = details.fileSize >= baseCallback_->detectRenameThreshold_ ? +// Utility::retrieveFileID(fullName) : +// Utility::FileID(); + output_.addSubFile(shortName, FileDescriptor(details.lastWriteTimeRaw, details.fileSize)); //add 1 element to the progress indicator @@ -212,7 +231,7 @@ TraverseCallback::ReturnValue BaseDirCallback::onFile( const Zstring& fullName, const TraverseCallback::FileInfo& details) { - //do not scan the database file + //do not list the database file sync.ffs_db #ifdef FFS_WIN if (getSyncDBFilename().CmpNoCase(shortName) == 0) #elif defined FFS_LINUX @@ -228,14 +247,14 @@ TraverseCallback::ReturnValue BaseDirCallback::onFile( struct DirBufferKey { DirBufferKey(const Zstring& dirname, - const FilterProcess::FilterRef& filterIn) : //filter interface: always bound by design! + const BaseFilter::FilterRef& filterIn) : //filter interface: always bound by design! directoryName(dirname), filter(filterIn->isNull() ? //some optimization of "Null" filter - FilterProcess::FilterRef(new NullFilter) : + BaseFilter::FilterRef(new NullFilter) : filterIn) {} const Zstring directoryName; - const FilterProcess::FilterRef filter; //buffering has to consider filtering! + const BaseFilter::FilterRef filter; //buffering has to consider filtering! bool operator < (const DirBufferKey& b) const { @@ -256,11 +275,14 @@ struct DirBufferKey class CompareProcess::DirectoryBuffer //buffer multiple scans of the same directories { public: - DirectoryBuffer(const bool traverseDirectorySymlinks, StatusHandler* statusUpdater) : + DirectoryBuffer(const bool traverseDirectorySymlinks, + const unsigned int detectRenameThreshold, + StatusHandler* statusUpdater) : m_traverseDirectorySymlinks(traverseDirectorySymlinks), + detectRenameThreshold_(detectRenameThreshold), m_statusUpdater(statusUpdater) {} - const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, const FilterProcess::FilterRef& filter); + const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, const BaseFilter::FilterRef& filter); private: typedef boost::shared_ptr<DirContainer> DirBufferValue; //exception safety: avoid memory leak @@ -271,6 +293,7 @@ private: BufferType buffer; const bool m_traverseDirectorySymlinks; + const unsigned int detectRenameThreshold_; StatusHandler* m_statusUpdater; }; //------------------------------------------------------------------------------------------ @@ -282,10 +305,15 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK if (FreeFileSync::dirExists(newKey.directoryName.c_str())) //folder existence already checked in startCompareProcess(): do not treat as error when arriving here! { - std::auto_ptr<TraverseCallback> traverser(new BaseDirCallback(*baseContainer, newKey.filter, m_statusUpdater)); + std::auto_ptr<TraverseCallback> traverser(new BaseDirCallback(*baseContainer, + newKey.filter, + detectRenameThreshold_, + m_statusUpdater)); //get all files and folders from directoryPostfixed (and subdirectories) - traverseFolder(newKey.directoryName, m_traverseDirectorySymlinks, traverser.get()); //exceptions may be thrown! + traverseFolder(newKey.directoryName, + m_traverseDirectorySymlinks, + traverser.get()); //exceptions may be thrown! } return *baseContainer.get(); } @@ -293,7 +321,7 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK const DirContainer& CompareProcess::DirectoryBuffer::getDirectoryDescription( const Zstring& directoryPostfixed, - const FilterProcess::FilterRef& filter) + const BaseFilter::FilterRef& filter) { const DirBufferKey searchKey(directoryPostfixed, filter); @@ -321,14 +349,14 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF checkEmptyDirnameActive = false; while (true) { - const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Please fill all empty directory fields.")) + wxT(" \n\n") + + const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("At least one directory input field is empty.")) + wxT(" \n\n") + + wxT("(") + additionalInfo + wxT(")")); if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop else - throw std::logic_error("Programming Error: Unknown return value!"); + throw std::logic_error("Programming Error: Unknown return value! (1)"); } } } @@ -339,13 +367,13 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF { ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT(" \n") + wxT("\"") + zToWx(i->leftDirectory) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo); + additionalInfo + wxT(" ") + FreeFileSync::getLastErrorFormatted()); if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop else - throw std::logic_error("Programming Error: Unknown return value!"); + throw std::logic_error("Programming Error: Unknown return value! (2)"); } if (!i->rightDirectory.empty()) @@ -353,13 +381,13 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF { ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT("\n") + wxT("\"") + zToWx(i->rightDirectory) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo); + additionalInfo + wxT(" ") + FreeFileSync::getLastErrorFormatted()); if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop else - throw std::logic_error("Programming Error: Unknown return value!"); + throw std::logic_error("Programming Error: Unknown return value! (3)"); } } } @@ -372,8 +400,8 @@ bool dependencyExists(const std::set<Zstring>& folders, const Zstring& newFolder Zstring newFolderFmt = newFolder; Zstring refFolderFmt = *i; #ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case - newFolderFmt.MakeLower(); - refFolderFmt.MakeLower(); + newFolderFmt.MakeUpper(); + refFolderFmt.MakeUpper(); #elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case //nothing to do here #endif @@ -419,6 +447,7 @@ bool foldersHaveDependencies(const std::vector<FolderPairCfg>& folderPairsFrom, CompareProcess::CompareProcess(const bool traverseSymLinks, const unsigned int fileTimeTol, const bool ignoreOneHourDiff, + const unsigned int detectRenameThreshold, xmlAccess::OptionalDialogs& warnings, StatusHandler* handler) : fileTimeTolerance(fileTimeTol), @@ -427,7 +456,7 @@ CompareProcess::CompareProcess(const bool traverseSymLinks, statusUpdater(handler), txtComparingContentOfFiles(wxToZ(_("Comparing content of files %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)) { - directoryBuffer.reset(new DirectoryBuffer(traverseSymLinks, handler)); + directoryBuffer.reset(new DirectoryBuffer(traverseSymLinks, detectRenameThreshold, handler)); } @@ -447,7 +476,7 @@ bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, Co static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]); #ifdef FFS_WIN - wxFFile file1(filename1.c_str(), DefaultStr("rb")); + wxFFile file1(FreeFileSync::applyLongPathPrefix(filename1).c_str(), DefaultStr("rb")); #elif defined FFS_LINUX wxFFile file1(::fopen(filename1.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename #endif @@ -455,7 +484,7 @@ bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, Co throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(filename1) + wxT("\"")); #ifdef FFS_WIN - wxFFile file2(filename2.c_str(), DefaultStr("rb")); + wxFFile file2(FreeFileSync::applyLongPathPrefix(filename2).c_str(), DefaultStr("rb")); #elif defined FFS_LINUX wxFFile file2(::fopen(filename2.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename #endif @@ -551,7 +580,7 @@ struct ToBeRemoved class RemoveFilteredDirs { public: - RemoveFilteredDirs(const FilterProcess& filterProc) : + RemoveFilteredDirs(const BaseFilter& filterProc) : filterProc_(filterProc) {} void execute(HierarchyObject& hierObj) @@ -573,7 +602,7 @@ private: execute(dirObj); } - const FilterProcess& filterProc_; + const BaseFilter& filterProc_; }; @@ -695,15 +724,25 @@ wxString getConflictInvalidDate(const Zstring& fileNameFull, const wxLongLong& u } +namespace +{ +inline +void makeSameLength(wxString& first, wxString& second) +{ + const size_t maxPref = std::max(first.length(), second.length()); + first.Pad(maxPref - first.length(), wxT(' '), true); + second.Pad(maxPref - second.length(), wxT(' '), true); +} +} + + //check for changed files with same modification date wxString getConflictSameDateDiffSize(const FileMapping& fileObj) { //some beautification... wxString left = wxString(_("Left")) + wxT(": "); wxString right = wxString(_("Right")) + wxT(": "); - const size_t maxPref = std::max(left.length(), right.length()); - left.Pad(maxPref - left.length(), wxT(' '), true); - right.Pad(maxPref - right.length(), wxT(' '), true); + makeSameLength(left, right); wxString msg = _("Files %x have the same date but a different size!"); msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileObj.getRelativeName<LEFT_SIDE>()) + wxT("\"")); @@ -722,9 +761,7 @@ wxString getConflictChangeWithinHour(const FileMapping& fileObj) //some beautification... wxString left = wxString(_("Left")) + wxT(": "); wxString right = wxString(_("Right")) + wxT(": "); - const size_t maxPref = std::max(left.length(), right.length()); - left.Pad(maxPref - left.length(), wxT(' '), true); - right.Pad(maxPref - right.length(), wxT(' '), true); + makeSameLength(left, right); wxString msg = _("Files %x have a file time difference of less than 1 hour!\n\nIt's not safe to decide which one is newer due to Daylight Saving Time issues."); msg += wxString(wxT("\n")) + _("(Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".)"); @@ -880,7 +917,7 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director - const size_t objectsTotal = filesToCompareBytewise.size() * 2; + const size_t objectsTotal = filesToCompareBytewise.size() * 2; const wxULongLong bytesTotal = getBytesToCompare(filesToCompareBytewise); statusUpdater->initNewProcess(objectsTotal, @@ -1060,4 +1097,3 @@ void CompareProcess::performBaseComparison(BaseDirMapping& output, std::vector<F MergeSides(appendUndefined).execute(directoryLeft, directoryRight, output); } - diff --git a/comparison.h b/comparison.h index 3a7492c6..59ee582c 100644 --- a/comparison.h +++ b/comparison.h @@ -13,7 +13,7 @@ struct FolderPairCfg { FolderPairCfg(const Zstring& leftDir, const Zstring& rightDir, - const FilterProcess::FilterRef& filterIn, + const BaseFilter::FilterRef& filterIn, const SyncConfiguration& syncCfg) : leftDirectory(leftDir), rightDirectory(rightDir), @@ -23,7 +23,7 @@ struct FolderPairCfg Zstring leftDirectory; Zstring rightDirectory; - FilterProcess::FilterRef filter; //filter interface: always bound by design! + BaseFilter::FilterRef filter; //filter interface: always bound by design! SyncConfiguration syncConfiguration; }; @@ -34,9 +34,13 @@ std::vector<FolderPairCfg> extractCompareCfg(const MainConfiguration& mainCfg); class CompareProcess { public: - CompareProcess(const bool traverseSymLinks, - const unsigned int fileTimeTol, - const bool ignoreOneHourDiff, + CompareProcess(bool traverseSymLinks, + unsigned int fileTimeTol, + bool ignoreOneHourDiff, +#ifndef _MSC_VER +#warning remove threshold, if not used! +#endif + unsigned int detectRenameThreshold, xmlAccess::OptionalDialogs& warnings, StatusHandler* handler); diff --git a/fileHierarchy.cpp b/fileHierarchy.cpp index e27d9421..6316edf9 100644 --- a/fileHierarchy.cpp +++ b/fileHierarchy.cpp @@ -8,9 +8,11 @@ #include "shared/fileHandling.h" #include <wx/mstream.h> #include "shared/serialize.h" +#include "shared/buildInfo.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" +#include "shared/longPathPrefix.h" #endif using namespace FreeFileSync; @@ -110,7 +112,10 @@ SyncOperation FileSystemObject::getSyncOperation(const CompareFilesResult cmpRes const bool selectedForSynchronization, const SyncDirectionIntern syncDir) { - if (!selectedForSynchronization) return SO_DO_NOTHING; + if (!selectedForSynchronization) + return cmpResult == FILE_EQUAL ? + SO_EQUAL : + SO_DO_NOTHING; switch (cmpResult) { @@ -173,7 +178,7 @@ SyncOperation FileSystemObject::getSyncOperation(const CompareFilesResult cmpRes case FILE_EQUAL: assert(syncDir == SYNC_DIR_INT_NONE); - return SO_DO_NOTHING; + return SO_EQUAL; } return SO_DO_NOTHING; //dummy @@ -194,7 +199,7 @@ const Zstring& FreeFileSync::getSyncDBFilename() //------------------------------------------------------------------------------------------------------------------------------- const char FILE_FORMAT_DESCR[] = "FreeFileSync"; -const int FILE_FORMAT_VER = 3; +const int FILE_FORMAT_VER = Utility::is64BitBuild ? -3 : 3; //32 and 64 bit builds are binary incompatible! So give them different IDs //------------------------------------------------------------------------------------------------------------------------------- @@ -204,7 +209,7 @@ public: ReadDirInfo(wxInputStream& stream, const wxString& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName) { //read filter settings - dirInfo.filter = FilterProcess::loadFilter(stream_); + dirInfo.filter = BaseFilter::loadFilter(stream_); check(); //start recursion @@ -234,8 +239,12 @@ private: const unsigned long sizeHigh = readNumberC<unsigned long>(); const unsigned long sizeLow = readNumberC<unsigned long>(); + //const Utility::FileID fileIdentifier(stream_); + //check(); + dirCont.addSubFile(shortName, - FileDescriptor(wxLongLong(modHigh, modLow), wxULongLong(sizeHigh, sizeLow))); + FileDescriptor(wxLongLong(modHigh, modLow), + wxULongLong(sizeHigh, sizeLow))); } void readSubDirectory(DirContainer& dirCont) @@ -400,6 +409,9 @@ private: writeNumberC<unsigned long>(fileMap.getLastWriteTime<side>().GetLo()); // writeNumberC<unsigned long>(fileMap.getFileSize<side>().GetHi()); //filesize writeNumberC<unsigned long>(fileMap.getFileSize<side>().GetLo()); // + + //fileMap.getFileID<side>().toStream(stream_); //unique file identifier + //check(); } } @@ -464,7 +476,7 @@ void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (Fi //(try to) hide database file #ifdef FFS_WIN output.Close(); - ::SetFileAttributes(filename.c_str(), FILE_ATTRIBUTE_HIDDEN); + ::SetFileAttributes(FreeFileSync::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); #endif } @@ -533,7 +545,6 @@ void FreeFileSync::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileEr removeFile(baseMapping.getDBFilename<RIGHT_SIDE>(), false); renameFile(fileNameLeftTmp, baseMapping.getDBFilename<LEFT_SIDE>()); //throw (FileError); renameFile(fileNameRightTmp, baseMapping.getDBFilename<RIGHT_SIDE>()); //throw (FileError); - } catch (...) { @@ -548,3 +559,4 @@ void FreeFileSync::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileEr } } + diff --git a/fileHierarchy.h b/fileHierarchy.h index d26d527e..ca029354 100644 --- a/fileHierarchy.h +++ b/fileHierarchy.h @@ -11,6 +11,7 @@ #include <boost/shared_ptr.hpp> #include "shared/guid.h" #include "library/filter.h" +#include "shared/fileID.h" class DirectoryBuffer; @@ -19,11 +20,16 @@ namespace FreeFileSync { struct FileDescriptor { - FileDescriptor(const wxLongLong& lastWriteTimeRawIn, const wxULongLong& fileSizeIn) : + FileDescriptor(const wxLongLong& lastWriteTimeRawIn, + const wxULongLong& fileSizeIn) : + //const Utility::FileID fileId) : lastWriteTimeRaw(lastWriteTimeRawIn), fileSize(fileSizeIn) {} - wxLongLong lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) + wxLongLong lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) wxULongLong fileSize; + + //#warning: what about memory consumption?? (assume large comparisons!!?) + //Utility::FileID fileIdentifier; //unique file identifier, optional: may be NULL! }; @@ -96,7 +102,7 @@ private: struct DirInformation { //filter settings (used when retrieving directory data) - FilterProcess::FilterRef filter; + BaseFilter::FilterRef filter; //hierarchical directory information DirContainer baseDirContainer; @@ -198,7 +204,7 @@ class FileSystemObject public: const Zstring getParentRelativeName() const; //get name relative to base sync dir without FILE_NAME_SEPARATOR postfix const Zstring getObjRelativeName() const; //same as getRelativeName() but also returns value if either side is empty - const Zstring& getObjShortName() const; //same as getShortName() but also returns value if either side is empty + const Zstring& getObjShortName() const; //same as getShortName() but also returns value if either side is empty template <SelectedSide side> bool isEmpty() const; template <SelectedSide side> const Zstring& getShortName() const; template <SelectedSide side> const Zstring getRelativeName() const; //get name relative to base sync dir without FILE_NAME_SEPARATOR prefix @@ -310,6 +316,7 @@ class FileMapping : public FileSystemObject public: template <SelectedSide side> const wxLongLong& getLastWriteTime() const; template <SelectedSide side> const wxULongLong& getFileSize() const; + //template <SelectedSide side> const Utility::FileID& getFileID() const; virtual CompareFilesResult getCategory() const; virtual const wxString& getCatConflict() const; @@ -367,16 +374,16 @@ class BaseDirMapping : public HierarchyObject //synchronization base directory public: BaseDirMapping(const Zstring& dirPostfixedLeft, const Zstring& dirPostfixedRight, - const FilterProcess::FilterRef& filterIn) : + const BaseFilter::FilterRef& filterIn) : HierarchyObject(dirPostfixedLeft, dirPostfixedRight), filter(filterIn) {} - const FilterProcess::FilterRef& getFilter() const; + const BaseFilter::FilterRef& getFilter() const; template <SelectedSide side> Zstring getDBFilename() const; virtual void swap(); private: - FilterProcess::FilterRef filter; + BaseFilter::FilterRef filter; }; @@ -384,8 +391,9 @@ typedef std::vector<BaseDirMapping> FolderComparison; //------------------------------------------------------------------ - - +//convenience methods +//test whether FileSystemObject is a DirMapping +bool isDirectoryMapping(const FileSystemObject& fsObj); @@ -819,7 +827,7 @@ void DirMapping::copyToR() inline -const FilterProcess::FilterRef& BaseDirMapping::getFilter() const +const BaseFilter::FilterRef& BaseDirMapping::getFilter() const { return filter; } @@ -888,7 +896,7 @@ inline void FileMapping::removeObjectL() { cmpResult = FILE_RIGHT_SIDE_ONLY; - dataLeft = FileDescriptor(0, 0); + dataLeft = FileDescriptor(0, 0); } @@ -904,7 +912,9 @@ inline void FileMapping::copyToL() { cmpResult = FILE_EQUAL; - dataLeft = dataRight; + dataLeft = FileDescriptor(dataRight.lastWriteTimeRaw, + dataRight.fileSize); + //Utility::FileID()); //attention! do not copy FileID! It is retained on file renaming only! } @@ -912,7 +922,9 @@ inline void FileMapping::copyToR() { cmpResult = FILE_EQUAL; - dataRight = dataLeft; + dataRight = FileDescriptor(dataLeft.lastWriteTimeRaw, + dataLeft.fileSize); + //Utility::FileID()); //attention! do not copy FileID! It is retained on file renaming only! } @@ -946,6 +958,31 @@ const wxULongLong& FileMapping::getFileSize<RIGHT_SIDE>() const { return dataRight.fileSize; } + + +//template <> +//inline +//const Utility::FileID& FileMapping::getFileID<LEFT_SIDE>() const +//{ +// return dataLeft.fileIdentifier; +//} +// +// +//template <> +//inline +//const Utility::FileID& FileMapping::getFileID<RIGHT_SIDE>() const +//{ +// return dataRight.fileIdentifier; +//} + +inline +bool isDirectoryMapping(const FileSystemObject& fsObj) +{ + return dynamic_cast<const DirMapping*>(&fsObj) != NULL; +} + } #endif // FILEHIERARCHY_H_INCLUDED + + diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index 6c72859c..cba76f57 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -242,7 +242,7 @@ public: } //get filename in order to retrieve the icon from it - virtual Zstring getIconFile(const unsigned int row) const = 0; + virtual Zstring getIconFile(const unsigned int row) const = 0; //return "folder" if row points to a folder protected: template <SelectedSide side> @@ -311,7 +311,7 @@ private: if (!fsObj->isActive()) return COLOR_BLUE; //mark directories - else if (dynamic_cast<const DirMapping*>(fsObj) != NULL) + else if (isDirectoryMapping(*fsObj)) return COLOR_GREY; else return *wxWHITE; @@ -332,13 +332,18 @@ public: return CustomGridTableRim::GetValueSub<LEFT_SIDE>(row, col); } - virtual Zstring getIconFile(const unsigned int row) const + virtual Zstring getIconFile(const unsigned int row) const //return "folder" if row points to a folder { const FileSystemObject* fsObj = getRawData(row); if (fsObj && !fsObj->isEmpty<LEFT_SIDE>()) - return fsObj->getFullName<LEFT_SIDE>(); - else - return Zstring(); + { + if (isDirectoryMapping(*fsObj)) //it's a directory icon + return DefaultStr("folder"); + else + return fsObj->getFullName<LEFT_SIDE>(); + } + + return Zstring(); } }; @@ -351,20 +356,25 @@ public: return CustomGridTableRim::GetValueSub<RIGHT_SIDE>(row, col); } - virtual Zstring getIconFile(const unsigned int row) const + virtual Zstring getIconFile(const unsigned int row) const //return "folder" if row points to a folder { const FileSystemObject* fsObj = getRawData(row); if (fsObj && !fsObj->isEmpty<RIGHT_SIDE>()) { - //Optimization: if filename exists on both sides, always use left side's file: - //Icon should be the same on both sides anyway... - if (!fsObj->isEmpty<LEFT_SIDE>()) - return fsObj->getFullName<LEFT_SIDE>(); + if (isDirectoryMapping(*fsObj)) //it's a directory icon + return DefaultStr("folder"); else - return fsObj->getFullName<RIGHT_SIDE>(); + { + //Optimization: if filename exists on both sides, always use left side's file: + //Icon should be the same on both sides anyway... + if (!fsObj->isEmpty<LEFT_SIDE>()) + return fsObj->getFullName<LEFT_SIDE>(); + else + return fsObj->getFullName<RIGHT_SIDE>(); + } } - else - return Zstring(); + + return Zstring(); } }; @@ -435,6 +445,7 @@ private: case SO_UNRESOLVED_CONFLICT: return COLOR_YELLOW; case SO_DO_NOTHING: + case SO_EQUAL: return *wxWHITE; } } @@ -873,9 +884,9 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col) if (col == m_marker.first) { if (m_marker.second == ASCENDING) - dc.DrawBitmap(*GlobalResources::getInstance().bitmapSmallUp, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border + dc.DrawBitmap(GlobalResources::getInstance().getImageByName(wxT("smallUp")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border else - dc.DrawBitmap(*GlobalResources::getInstance().bitmapSmallDown, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border + dc.DrawBitmap(GlobalResources::getInstance().getImageByName(wxT("smallDown")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border } } @@ -980,39 +991,48 @@ public: const Zstring fileName = m_gridDataTable->getIconFile(row); if (!fileName.empty()) { - wxIcon icon; - bool iconDrawnFully = false; - const bool iconLoaded = IconBuffer::getInstance().requestIcon(fileName, &icon); //returns false if icon is not in buffer - if (iconLoaded) + //first check if it is a directory icon: + if (fileName == DefaultStr("folder")) { - dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY()); + dc.DrawIcon(IconBuffer::getDirectoryIcon(), rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY()); + m_loadIconSuccess[row] = true; //save status of last icon load -> used for async. icon loading + } + else //retrieve file icon + { + wxIcon icon; + bool iconDrawnFully = false; + const bool iconLoaded = IconBuffer::getInstance().requestFileIcon(fileName, &icon); //returns false if icon is not in buffer + if (iconLoaded) + { + dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY()); - //----------------------------------------------------------------------------------------------- - //only mark as successful if icon was drawn fully! - //(attention: when scrolling, rows get partially updated, which can result in the upper half being blank!) + //----------------------------------------------------------------------------------------------- + //only mark as successful if icon was drawn fully! + //(attention: when scrolling, rows get partially updated, which can result in the upper half being blank!) - //rect where icon was placed - wxRect iconRect(rect); //unscrolled - iconRect.x += LEFT_BORDER; - iconRect.SetWidth(IconBuffer::ICON_SIZE); + //rect where icon was placed + wxRect iconRect(rect); //unscrolled + iconRect.x += LEFT_BORDER; + iconRect.SetWidth(IconBuffer::ICON_SIZE); - //convert to scrolled coordinates - grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y); + //convert to scrolled coordinates + grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y); - wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion()); - while (regionsInv) - { - if (regionsInv.GetRect().Contains(iconRect)) + wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion()); + while (regionsInv) { - iconDrawnFully = true; - break; + if (regionsInv.GetRect().Contains(iconRect)) + { + iconDrawnFully = true; + break; + } + ++regionsInv; } - ++regionsInv; } + //----------------------------------------------------------------------------------------------- + //save status of last icon load -> used for async. icon loading + m_loadIconSuccess[row] = iconLoaded && iconDrawnFully; } - //----------------------------------------------------------------------------------------------- - //save status of last icon load -> used for async. icon loading - m_loadIconSuccess[row] = iconLoaded && iconDrawnFully; } } return; @@ -1364,7 +1384,7 @@ void CustomGridRim::getIconsToBeLoaded(std::vector<Zstring>& newLoad) //loads al if (!fileName.empty()) { //test if they are already loaded in buffer: - if (FreeFileSync::IconBuffer::getInstance().requestIcon(fileName)) + if (FreeFileSync::IconBuffer::getInstance().requestFileIcon(fileName)) { //exists in buffer: refresh Row for (int k = 0; k < totalCols; ++k) @@ -1644,28 +1664,31 @@ void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos) switch (syncOp) { case SO_CREATE_NEW_LEFT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncCreateLeftAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncCreateLeftAct"))); break; case SO_CREATE_NEW_RIGHT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncCreateRightAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncCreateRightAct"))); break; case SO_DELETE_LEFT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncDeleteLeftAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDeleteLeftAct"))); break; case SO_DELETE_RIGHT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncDeleteRightAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDeleteRightAct"))); break; case SO_OVERWRITE_LEFT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncDirLeftAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirLeftAct"))); break; case SO_OVERWRITE_RIGHT: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncDirRightAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirRightAct"))); break; case SO_DO_NOTHING: - toolTip->show(getDescription(syncOp), pos, GlobalResources::getInstance().bitmapSyncDirNoneAct); + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirNoneAct"))); + break; + case SO_EQUAL: + toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("equalAct"))); break; case SO_UNRESOLVED_CONFLICT: - toolTip->show(fsObj->getSyncOpConflict(), pos, GlobalResources::getInstance().bitmapConflictAct); + toolTip->show(fsObj->getSyncOpConflict(), pos, &GlobalResources::getInstance().getImageByName(wxT("conflictAct"))); break; }; } @@ -1675,25 +1698,25 @@ void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos) switch (cmpRes) { case FILE_LEFT_SIDE_ONLY: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapLeftOnlyAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("leftOnlyAct"))); break; case FILE_RIGHT_SIDE_ONLY: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapRightOnlyAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("rightOnlyAct"))); break; case FILE_LEFT_NEWER: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapLeftNewerAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("leftNewerAct"))); break; case FILE_RIGHT_NEWER: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapRightNewerAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("rightNewerAct"))); break; case FILE_DIFFERENT: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapDifferentAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("differentAct"))); break; case FILE_EQUAL: - toolTip->show(getDescription(cmpRes), pos, GlobalResources::getInstance().bitmapEqualAct); + toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("equalAct"))); break; case FILE_CONFLICT: - toolTip->show(fsObj->getCatConflict(), pos, GlobalResources::getInstance().bitmapConflictAct); + toolTip->show(fsObj->getCatConflict(), pos, &GlobalResources::getInstance().getImageByName(wxT("conflictAct"))); break; } } @@ -1767,26 +1790,32 @@ int CustomGridMiddle::mousePosToRow(const wxPoint pos, BlockPosition* block) if (block) { *block = BLOCKPOS_CHECK_BOX; //default - if (gridDataTable->syncPreviewIsActive() && - row >= 0) - { - // cell: - // ---------------------------------- - // | checkbox | left | middle | right| - // ---------------------------------- - const wxRect rect = CellToRect(row, 0); - if (rect.GetWidth() > CHECK_BOX_WIDTH) + if (row >= 0) + { + const FileSystemObject* const fsObj = gridDataTable->getRawData(row); + if ( fsObj != NULL && //if valid row... + gridDataTable->syncPreviewIsActive() && + fsObj->getSyncOperation() != SO_EQUAL) //in sync-preview equal files shall be treated as in cmp result, i.e. as full checkbox { - const double blockWidth = (rect.GetWidth() - CHECK_BOX_WIDTH) / 3.0; - if (rect.GetX() + CHECK_BOX_WIDTH <= x && x < rect.GetX() + rect.GetWidth()) + // cell: + // ---------------------------------- + // | checkbox | left | middle | right| + // ---------------------------------- + + const wxRect rect = CellToRect(row, 0); + if (rect.GetWidth() > CHECK_BOX_WIDTH) { - if (x - (rect.GetX() + CHECK_BOX_WIDTH) < blockWidth) - *block = BLOCKPOS_LEFT; - else if (x - (rect.GetX() + CHECK_BOX_WIDTH) < 2 * blockWidth) - *block = BLOCKPOS_MIDDLE; - else - *block = BLOCKPOS_RIGHT; + const double blockWidth = (rect.GetWidth() - CHECK_BOX_WIDTH) / 3.0; + if (rect.GetX() + CHECK_BOX_WIDTH <= x && x < rect.GetX() + rect.GetWidth()) + { + if (x - (rect.GetX() + CHECK_BOX_WIDTH) < blockWidth) + *block = BLOCKPOS_LEFT; + else if (x - (rect.GetX() + CHECK_BOX_WIDTH) < 2 * blockWidth) + *block = BLOCKPOS_MIDDLE; + else + *block = BLOCKPOS_RIGHT; + } } } } @@ -1831,22 +1860,23 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, rectShrinked.SetWidth(CHECK_BOX_WIDTH); wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); - //print image into first block + //print checkbox into first block rectShrinked.SetX(rect.GetX() + 1); - //HIGHLIGHTNING: - if (rowIsHighlighted && m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) + //HIGHLIGHTNING (checkbox): + if ( rowIsHighlighted && + m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) { if (fsObj->isActive()) - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxTrueFocus, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxTrueFocus")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); else - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxFalseFocus, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxFalseFocus")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); } //default else if (fsObj->isActive()) - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxTrue")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); else - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxFalse")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); //clean remaining block of rect that will receive image of checkbox/directions rectShrinked.SetWidth(rect.GetWidth() - CHECK_BOX_WIDTH); @@ -1858,8 +1888,9 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, { //print sync direction into second block - //HIGHLIGHTNING: - if (rowIsHighlighted && m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) + //HIGHLIGHTNING (sync direction): + if ( rowIsHighlighted && + m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) //don't allow changing direction for "=="-files switch (m_gridMiddle->highlightedPos) { case CustomGridMiddle::BLOCKPOS_CHECK_BOX: @@ -1885,25 +1916,25 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, switch (fsObj->getCategory()) { case FILE_LEFT_SIDE_ONLY: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapLeftOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("leftOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_RIGHT_SIDE_ONLY: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapRightOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("rightOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_LEFT_NEWER: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapLeftNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("leftNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_RIGHT_NEWER: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapRightNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("rightNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_DIFFERENT: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapDifferentSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("differentSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_EQUAL: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapEqualSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("equalSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; case FILE_CONFLICT: - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("conflictSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); break; } } @@ -1935,9 +1966,9 @@ void CustomGridMiddle::DrawColLabel(wxDC& dc, int col) const wxRect rect(GetColLeft(col), 0, GetColWidth(col), GetColLabelSize()); if (gridDataTable->syncPreviewIsActive()) - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapSyncViewSmall, rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("syncViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); else - dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCmpViewSmall, rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); + dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("cmpViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); } @@ -1946,21 +1977,23 @@ const wxBitmap& FreeFileSync::getSyncOpImage(SyncOperation syncOp) switch (syncOp) //evaluate comparison result and sync direction { case SO_CREATE_NEW_LEFT: - return *GlobalResources::getInstance().bitmapCreateLeftSmall; + return GlobalResources::getInstance().getImageByName(wxT("createLeftSmall")); case SO_CREATE_NEW_RIGHT: - return *GlobalResources::getInstance().bitmapCreateRightSmall; + return GlobalResources::getInstance().getImageByName(wxT("createRightSmall")); case SO_DELETE_LEFT: - return *GlobalResources::getInstance().bitmapDeleteLeftSmall; + return GlobalResources::getInstance().getImageByName(wxT("deleteLeftSmall")); case SO_DELETE_RIGHT: - return *GlobalResources::getInstance().bitmapDeleteRightSmall; + return GlobalResources::getInstance().getImageByName(wxT("deleteRightSmall")); case SO_OVERWRITE_RIGHT: - return *GlobalResources::getInstance().bitmapSyncDirRightSmall; + return GlobalResources::getInstance().getImageByName(wxT("syncDirRightSmall")); case SO_OVERWRITE_LEFT: - return *GlobalResources::getInstance().bitmapSyncDirLeftSmall; + return GlobalResources::getInstance().getImageByName(wxT("syncDirLeftSmall")); case SO_DO_NOTHING: - return *GlobalResources::getInstance().bitmapSyncDirNoneSmall; + return GlobalResources::getInstance().getImageByName(wxT("syncDirNoneSmall")); + case SO_EQUAL: + return GlobalResources::getInstance().getImageByName(wxT("equalSmall")); case SO_UNRESOLVED_CONFLICT: - return *GlobalResources::getInstance().bitmapConflictSmall; + return GlobalResources::getInstance().getImageByName(wxT("conflictSmall")); } return wxNullBitmap; //dummy @@ -1970,3 +2003,8 @@ const wxBitmap& FreeFileSync::getSyncOpImage(SyncOperation syncOp) + + + + + diff --git a/library/FreeFileSync.xpm b/library/FreeFileSync.xpm deleted file mode 100644 index 339ccccb..00000000 --- a/library/FreeFileSync.xpm +++ /dev/null @@ -1,425 +0,0 @@ -/* XPM */ -static const char * FreeFileSync_xpm[] = { -"32 32 390 2", -" c None", -". c #005927", -"+ c #046A38", -"@ c #1B7E4B", -"# c #318F5A", -"$ c #308F56", -"% c #258C4D", -"& c #128040", -"* c #036C36", -"= c #005A31", -"- c #005D28", -"; c #1F7D4E", -"> c #76B08F", -", c #ADD9B7", -"' c #B9EABB", -") c #A5E9A5", -"! c #8BE38A", -"~ c #6DDB6D", -"{ c #4DD04E", -"] c #2FC136", -"^ c #19A82F", -"/ c #078433", -"( c #005D33", -"_ c #036B35", -": c #6FAA8C", -"< c #D9EEDE", -"[ c #E0FDDD", -"} c #BDF3BB", -"| c #9BE89A", -"1 c #7DE07C", -"2 c #5FD85F", -"3 c #44D143", -"4 c #32D131", -"5 c #2AD929", -"6 c #25E422", -"7 c #1CE31C", -"8 c #0CB522", -"9 c #017235", -"0 c #0B6F3B", -"a c #9EC8B0", -"b c #EEFFEC", -"c c #CAF5C9", -"d c #A7EAA7", -"e c #8AE38A", -"f c #6EDB6E", -"g c #51D351", -"h c #39CF38", -"i c #2CD32B", -"j c #26DB26", -"k c #20E11F", -"l c #19E719", -"m c #13EF12", -"n c #0CFE08", -"o c #03DB0F", -"p c #007F31", -"q c #056B36", -"r c #98C7AA", -"s c #E3FEE0", -"t c #B8EEB7", -"u c #99E699", -"v c #7DDF7D", -"w c #60D760", -"x c #45D144", -"y c #33D530", -"z c #2ADA28", -"A c #23DC23", -"B c #1CE41C", -"C c #16F113", -"D c #0FF90C", -"E c #08FA07", -"F c #02FE02", -"G c #00FF00", -"H c #00E20A", -"I c #007434", -"J c #005E2F", -"K c #005E30", -"L c #005B2E", -"M c #005D2E", -"N c #6BAB87", -"O c #D5FAD2", -"P c #AAEAAA", -"Q c #8CE28C", -"R c #70DB70", -"S c #53D453", -"T c #3BD13A", -"U c #2DD42C", -"V c #1CB72C", -"W c #0D9830", -"X c #078931", -"Y c #068D2F", -"Z c #06A527", -"` c #04CF14", -" . c #00FC02", -".. c #00C914", -"+. c #1A8347", -"@. c #5ABA6B", -"#. c #4FBA60", -"$. c #36AA4A", -"%. c #299E42", -"&. c #8FDF92", -"*. c #81DE81", -"=. c #65D665", -"-. c #47D047", -";. c #33D232", -">. c #27CE2A", -",. c #0D8F30", -"'. c #005A2F", -"). c #005F33", -"!. c #008A2C", -"~. c #00D210", -"{. c #009629", -"]. c #369C56", -"^. c #81E87D", -"/. c #66DE63", -"(. c #50D94D", -"_. c #3BD538", -":. c #2CD52B", -"<. c #2DDD2D", -"[. c #34E034", -"}. c #2FDB2F", -"|. c #29D728", -"1. c #25D228", -"2. c #098033", -"3. c #00502E", -"4. c #006536", -"5. c #00A820", -"6. c #00F802", -"7. c #00D510", -"8. c #005D31", -"9. c #1D8945", -"0. c #60D860", -"a. c #4AD34A", -"b. c #36CF36", -"c. c #2BD42B", -"d. c #22DC22", -"e. c #19E419", -"f. c #0FED0F", -"g. c #08F608", -"h. c #05FE03", -"i. c #05E80B", -"j. c #009E21", -"k. c #006832", -"l. c #005734", -"m. c #009029", -"n. c #00EF05", -"o. c #00832D", -"p. c #057238", -"q. c #40C646", -"r. c #38D137", -"s. c #1BE41B", -"t. c #13ED13", -"u. c #0AF50A", -"v. c #02FD02", -"w. c #00DF0C", -"x. c #008730", -"y. c #004F30", -"z. c #00852C", -"A. c #00F105", -"B. c #00B41F", -"C. c #005E32", -"D. c #1DA434", -"E. c #2EDA2B", -"F. c #00A426", -"G. c #008C27", -"H. c #00B91B", -"I. c #098234", -"J. c #23DB23", -"K. c #1CE61B", -"L. c #00C019", -"M. c #006131", -"N. c #006233", -"O. c #006E2B", -"P. c #00622F", -"Q. c #006535", -"R. c #12BD23", -"S. c #14F511", -"T. c #00EE07", -"U. c #00A424", -"V. c #00612F", -"W. c #3A8D63", -"X. c #8ABBA3", -"Y. c #B3D1C2", -"Z. c #468F6D", -"`. c #005E2A", -" + c #038230", -".+ c #0AEF0C", -"++ c #03FF02", -"@+ c #00F703", -"#+ c #007931", -"$+ c #006230", -"%+ c #509A75", -"&+ c #BBD6C9", -"*+ c #FEFEFF", -"=+ c #FFFFFF", -"-+ c #E6F2EB", -";+ c #1F7C4D", -">+ c #005D35", -",+ c #009624", -"'+ c #00FC01", -")+ c #00ED07", -"!+ c #00BC1A", -"~+ c #00812F", -"{+ c #004E2E", -"]+ c #378C60", -"^+ c #B5D5C3", -"/+ c #FAFFFA", -"(+ c #FBFFF9", -"_+ c #ECFCEB", -":+ c #E1F8E1", -"<+ c #D8F6D8", -"[+ c #DBFCD8", -"}+ c #7BBE8F", -"|+ c #009022", -"1+ c #009823", -"2+ c #007030", -"3+ c #00492B", -"4+ c #046734", -"5+ c #65AE81", -"6+ c #D0F3D1", -"7+ c #D8FBD6", -"8+ c #C3F2C3", -"9+ c #B7EEB7", -"0+ c #AEECAE", -"a+ c #A5EAA5", -"b+ c #9CE79C", -"c+ c #94E694", -"d+ c #89E189", -"e+ c #198446", -"f+ c #31895D", -"g+ c #116C44", -"h+ c #00502A", -"i+ c #036230", -"j+ c #62B878", -"k+ c #AEF1AC", -"l+ c #9DE99C", -"m+ c #8FE38F", -"n+ c #86E186", -"o+ c #7CDE7C", -"p+ c #73DC73", -"q+ c #6AD96A", -"r+ c #61D761", -"s+ c #57D457", -"t+ c #53D951", -"u+ c #2CA941", -"v+ c #005F31", -"w+ c #549F7A", -"x+ c #B0D0C1", -"y+ c #0B6A38", -"z+ c #0D773D", -"A+ c #6EDB6F", -"B+ c #6BDF67", -"C+ c #5DD65D", -"D+ c #55D355", -"E+ c #4BD24B", -"F+ c #43D143", -"G+ c #3BD13B", -"H+ c #34D234", -"I+ c #2DD42D", -"J+ c #27D827", -"K+ c #22DF21", -"L+ c #1BDB1E", -"M+ c #027A34", -"N+ c #167646", -"O+ c #EDFBEE", -"P+ c #9FCDAF", -"Q+ c #0A6E39", -"R+ c #168C3B", -"S+ c #2BC034", -"T+ c #28D828", -"U+ c #21DD21", -"V+ c #1EE01E", -"W+ c #1AE41A", -"X+ c #15E915", -"Y+ c #10EE10", -"Z+ c #0CF30C", -"`+ c #08F808", -" @ c #05FB04", -".@ c #03FE02", -"+@ c #01A323", -"@@ c #00592A", -"#@ c #88C79A", -"$@ c #DBFFD5", -"%@ c #88CB97", -"&@ c #157942", -"*@ c #006732", -"=@ c #1FB431", -"-@ c #24EC22", -";@ c #0CF40C", -">@ c #00C515", -",@ c #005A33", -"'@ c #309358", -")@ c #A4ECA3", -"!@ c #A3EDA0", -"~@ c #7DD584", -"{@ c #288E4B", -"]@ c #006232", -"^@ c #0F8535", -"/@ c #36C739", -"(@ c #35D334", -"_@ c #29D729", -":@ c #0FF10F", -"<@ c #05FB05", -"[@ c #01FE01", -"}@ c #00FE00", -"|@ c #00CB13", -"1@ c #006135", -"2@ c #016432", -"3@ c #5ABF68", -"4@ c #7AE377", -"5@ c #71DF6F", -"6@ c #66DB65", -"7@ c #39B04A", -"8@ c #11823A", -"9@ c #026633", -"0@ c #00522D", -"a@ c #036E34", -"b@ c #129E2E", -"c@ c #25D826", -"d@ c #22E221", -"e@ c #1DE41D", -"f@ c #19E919", -"g@ c #15ED15", -"h@ c #11F210", -"i@ c #039626", -"j@ c #008F2A", -"k@ c #00A323", -"l@ c #00A522", -"m@ c #008530", -"n@ c #00532D", -"o@ c #0F7F3D", -"p@ c #4BCE4E", -"q@ c #49D547", -"r@ c #41D040", -"s@ c #3ED63B", -"t@ c #33D133", -"u@ c #23BF2E", -"v@ c #17AF2C", -"w@ c #12AE2B", -"x@ c #11B826", -"y@ c #17D71E", -"z@ c #18EF15", -"A@ c #12F211", -"B@ c #05FC05", -"C@ c #00B919", -"D@ c #005C35", -"E@ c #0F8C35", -"F@ c #2AD52A", -"G@ c #27DE25", -"H@ c #21DE22", -"I@ c #1EE41D", -"J@ c #1BEC19", -"K@ c #17F314", -"L@ c #12F90F", -"M@ c #0DFD0A", -"N@ c #08FD06", -"O@ c #03FD03", -"P@ c #00CB12", -"Q@ c #006C37", -"R@ c #00562F", -"S@ c #07912F", -"T@ c #12E316", -"U@ c #0DFC0A", -"V@ c #09FA09", -"W@ c #01FF01", -"X@ c #00BE18", -"Y@ c #006D37", -"Z@ c #008030", -"`@ c #00C814", -" # c #00FA02", -".# c #00DD0C", -"+# c #009827", -"@# c #006437", -"## c #00852E", -"$# c #00B11E", -"%# c #00D111", -"&# c #00E40A", -"*# c #00EF06", -"=# c #00E908", -"-# c #00D80E", -";# c #00BD18", -"># c #009528", -",# c #006D35", -"'# c #004F2E", -")# c #00492C", -"!# c #006032", -"~# c #006A32", -"{# c #006D31", -"]# c #006B31", -"^# c #006533", -"/# c #005631", -" ", -" ", -" . + @ # $ % & * = ", -" - ; > , ' ) ! ~ { ] ^ / ( ", -" _ : < [ } | 1 2 3 4 5 6 7 8 9 ", -" 0 a b c d e f g h i j k l m n o p ", -" q r s t u v w x y z A B C D E F G H I ", -" J K L M N O P Q R S T U V W X Y Z ` .G G G ..( ", -" +.@.#.$.%.&.| *.=.-.;.>.,.'. ).!.~.G G G {. ", -" ].^./.(._.:.<.[.}.|.1.2.3. 4.5.6.G 7.8. ", -" 9.0.a.b.c.d.e.f.g.h.i.j.k. l.m.n.G o. ", -" p.q.r.c.A s.t.u.v.G G G w.x. y.z.A.B. ", -" C.D.E.A s.t.u.v.G G G G G F. G.H. ", -" I.J.K.t.u.v.G G G G G L.M. N.O.P. ", -" Q.R.S.u.v.G G G G T.U.= V.W.X.Y.Z.`. ", -" +.+++G G G @+L.#+ $+%+&+*+=+=+-+;+ ", -" >+,+'+G )+!+~+{+ ]+^+/+(+_+:+<+[+}+V. ", -" N.|+1+2+3+ 4+5+6+7+8+9+0+a+b+c+d+e+ ", -" f+g+h+ i+j+k+l+m+n+o+p+q+r+s+t+u+v+ ", -" w+x+y+ z+A+B+C+D+E+F+G+H+I+J+K+L+M+ ", -" N+O+P+Q+ L R+S+T+U+V+W+X+Y+Z+`+ @.@+@ ", -" @@#@$@%@&@ *@=@-@;@v.G G G G G G >@,@ ", -" '@)@!@~@{@]@ ^@/@(@_@s.:@<@[@}@G G |@1@ ", -" 2@3@4@5@6@7@8@9@0@ a@b@c@d@e@f@g@h@u.i@j@k@l@m@n@ ", -" o@p@q@r@s@t@u@v@w@x@y@z@A@;@`+B@F G C@D@ ", -" E@F@G@H@I@J@K@L@M@N@O@[@G G G G P@Q@ ", -" R@S@T@U@V@B@v.W@G G G G G G G X@Y@ ", -" Z@`@ #G G G G G G G G .#+#@# ", -" ( ##$#%#&#*#=#-#;#>#,#'# ", -" )#!#~#{#]#^#/# ", -" ", -" "}; diff --git a/library/Recycler/Recycler_Vista.vcproj b/library/Recycler/Recycler_Vista.vcproj new file mode 100644 index 00000000..65ab6609 --- /dev/null +++ b/library/Recycler/Recycler_Vista.vcproj @@ -0,0 +1,409 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9,00" + Name="Vista Recycler" + ProjectGUID="{70394AEF-5897-4911-AFA1-82EAF0581EFA}" + RootNamespace="ShadowDll" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + IntermediateDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + ConfigurationType="2" + CharacterSet="1" + BuildLogFile="$(IntDir)\Build.html" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;RECYCLER_DLL_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + SuppressStartupBanner="false" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="Recycler_$(PlatformName).dll" + LinkIncremental="1" + SuppressStartupBanner="false" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(IntDir)$(TargetName).pdb" + SubSystem="2" + ProfileGuidedDatabase="" + ImportLibrary="$(IntDir)$(TargetName).lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + IntermediateDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + ConfigurationType="2" + CharacterSet="1" + BuildLogFile="$(IntDir)\Build.html" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;RECYCLER_DLL_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + SuppressStartupBanner="false" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="Recycler_$(PlatformName).dll" + LinkIncremental="1" + SuppressStartupBanner="false" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(IntDir)$(TargetName).pdb" + SubSystem="2" + ProfileGuidedDatabase="" + ImportLibrary="$(IntDir)$(TargetName).lib" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + IntermediateDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + BuildLogFile="$(IntDir)\Build.html" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;RECYCLER_DLL_EXPORTS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + SuppressStartupBanner="false" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="Recycler_$(PlatformName).dll" + LinkIncremental="1" + SuppressStartupBanner="false" + GenerateDebugInformation="false" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + LinkTimeCodeGeneration="1" + ProfileGuidedDatabase="" + ImportLibrary="$(IntDir)$(TargetName).lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + IntermediateDirectory="OBJ\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + BuildLogFile="$(IntDir)\Build.html" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;RECYCLER_DLL_EXPORTS" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + SuppressStartupBanner="false" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="Recycler_$(PlatformName).dll" + LinkIncremental="1" + SuppressStartupBanner="false" + GenerateDebugInformation="false" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + LinkTimeCodeGeneration="1" + ProfileGuidedDatabase="" + ImportLibrary="$(IntDir)$(TargetName).lib" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Quelldateien" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\dllmain.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + CompileAsManaged="0" + /> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Headerdateien" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\recycler.cpp" + > + </File> + <File + RelativePath=".\recycler.h" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/library/Recycler/dllmain.cpp b/library/Recycler/dllmain.cpp new file mode 100644 index 00000000..834b4f88 --- /dev/null +++ b/library/Recycler/dllmain.cpp @@ -0,0 +1,22 @@ +// dllmain.cpp : Definiert den Einstiegspunkt für die DLL-Anwendung. + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/library/Recycler/recycler.cpp b/library/Recycler/recycler.cpp new file mode 100644 index 00000000..b551d4d0 --- /dev/null +++ b/library/Recycler/recycler.cpp @@ -0,0 +1,142 @@ +#include "recycler.h" + +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#include <Shellapi.h> // Included for shell constants such as FO_* values +#include <shobjidl.h> // Required for necessary shell dependencies + +#include <algorithm> +#include <string> +#include <cstdio> +#include <comdef.h> + + +void writeString(const wchar_t* input, wchar_t* output, size_t outputBufferLen) +{ + const size_t newSize = min(wcslen(input) + 1, outputBufferLen); //including null-termination + memcpy(output, input, newSize * sizeof(wchar_t)); + output[newSize-1] = 0; //if output buffer is too small... +} + + +std::wstring numberToHexString(const long number) +{ + wchar_t result[100]; + swprintf(result, 100, L"0x%08x", number); + return std::wstring(result); +} + + +void writeErrorMsg(const wchar_t* input, HRESULT hr, wchar_t* output, size_t outputBufferLen) +{ + std::wstring formattedMsg(input); + formattedMsg += L" ("; + formattedMsg += numberToHexString(hr); + formattedMsg += L": "; + formattedMsg += _com_error(hr).ErrorMessage(); + formattedMsg += L")"; + + writeString(formattedMsg.c_str(), output, outputBufferLen); +} + + +//IShellItem resource management +template <class T> +class ReleaseAtExit +{ +public: + ReleaseAtExit(T*& item) : item_(item) {} + ~ReleaseAtExit() + { + if (item_ != NULL) + item_->Release(); + } +private: + T*& item_; +}; + + +bool Utility::moveToRecycleBin(const wchar_t* fileNames[], + size_t fileNo, //size of fileNames array + wchar_t* errorMessage, + size_t errorBufferLen) +{ + HRESULT hr; + + // Create the IFileOperation interface + IFileOperation* pfo = NULL; + ReleaseAtExit<IFileOperation> dummy(pfo); + hr = CoCreateInstance(CLSID_FileOperation, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(&pfo)); + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"CoCreateInstance\".", hr, errorMessage, errorBufferLen); + return false; + } + + // Set the operation flags. Turn off all UI + // from being shown to the user during the + // operation. This includes error, confirmation + // and progress dialogs. + hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | + FOF_NOCONFIRMATION | + FOF_SILENT | + FOF_NOERRORUI); + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"SetOperationFlags\".", hr, errorMessage, errorBufferLen); + return false; + } + + for (size_t i = 0; i < fileNo; ++i) + { + //create file/folder item object + IShellItem* psiFile = NULL; + ReleaseAtExit<IShellItem> dummy2(psiFile); + hr = SHCreateItemFromParsingName(fileNames[i], + NULL, + IID_PPV_ARGS(&psiFile)); + if (FAILED(hr)) + { + std::wstring message(L"Error calling \"SHCreateItemFromParsingName\" for file "); + message += std::wstring(L"\"") + fileNames[i] + L"\"."; + writeErrorMsg(message.c_str(), hr, errorMessage, errorBufferLen); + return false; + } + + hr = pfo->DeleteItem(psiFile, NULL); + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"DeleteItem\".", hr, errorMessage, errorBufferLen); + return false; + } + } + + //perform actual operations + hr = pfo->PerformOperations(); + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"PerformOperations\".", hr, errorMessage, errorBufferLen); + return false; + } + + //check if errors occured: if FOFX_EARLYFAILURE is not used, PerformOperations() can return with success despite errors! + BOOL pfAnyOperationsAborted = FALSE; + hr = pfo->GetAnyOperationsAborted(&pfAnyOperationsAborted); + if (FAILED(hr)) + { + writeErrorMsg(L"Error calling \"GetAnyOperationsAborted\".", hr, errorMessage, errorBufferLen); + return false; + } + + + if (pfAnyOperationsAborted == TRUE) + { + writeString(L"Operation did not complete successfully.", errorMessage, errorBufferLen); + return false; + } + + return true; +} diff --git a/library/Recycler/recycler.h b/library/Recycler/recycler.h new file mode 100644 index 00000000..59bec9dc --- /dev/null +++ b/library/Recycler/recycler.h @@ -0,0 +1,24 @@ +#ifndef RECYCLER_DLL_H +#define RECYCLER_DLL_H + +#ifdef RECYCLER_DLL_EXPORTS +#define RECYCLER_DLL_API extern "C" __declspec(dllexport) +#else +#define RECYCLER_DLL_API extern "C" __declspec(dllimport) +#endif + + +namespace Utility +{ +//COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize + +RECYCLER_DLL_API +bool moveToRecycleBin(const wchar_t* fileNames[], + size_t fileNo, //size of fileNames array + wchar_t* errorMessage, + size_t errorBufferLen); +} + + + +#endif //RECYCLER_DLL_H diff --git a/library/ShadowCopy/Shadow_2003.vcproj b/library/ShadowCopy/Shadow_2003.vcproj index 560deb8d..49730440 100644 --- a/library/ShadowCopy/Shadow_2003.vcproj +++ b/library/ShadowCopy/Shadow_2003.vcproj @@ -205,7 +205,7 @@ Optimization="2" EnableIntrinsicFunctions="true" PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_2003" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" @@ -287,7 +287,7 @@ Optimization="2" EnableIntrinsicFunctions="true" PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_2003" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" diff --git a/library/ShadowCopy/Shadow_XP.vcproj b/library/ShadowCopy/Shadow_XP.vcproj index 6c1cbaaa..74b231de 100644 --- a/library/ShadowCopy/Shadow_XP.vcproj +++ b/library/ShadowCopy/Shadow_XP.vcproj @@ -205,7 +205,7 @@ Optimization="2" EnableIntrinsicFunctions="true" PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_XP" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" @@ -287,7 +287,7 @@ Optimization="2" EnableIntrinsicFunctions="true" PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_XP" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" diff --git a/library/ShadowCopy/shadow.cpp b/library/ShadowCopy/shadow.cpp index cbc4b085..0693815f 100644 --- a/library/ShadowCopy/shadow.cpp +++ b/library/ShadowCopy/shadow.cpp @@ -28,6 +28,7 @@ void writeString(const wchar_t* input, wchar_t* output, unsigned int outputBuffe { const size_t newSize = min(wcslen(input) + 1, outputBufferLen); //including null-termination memcpy(output, input, newSize * sizeof(wchar_t)); + output[newSize-1] = 0; //if output buffer is too small... } diff --git a/library/detectRenaming.cpp b/library/detectRenaming.cpp new file mode 100644 index 00000000..d2b4a62c --- /dev/null +++ b/library/detectRenaming.cpp @@ -0,0 +1,279 @@ +#include "detectRenaming.h" +#include <map> +#include <vector> +#include <boost/bind.hpp> + +using namespace FreeFileSync; + +/*detect renamed files: +Example: + X -> |_| Create right +|_| -> Y Delete right + +is detected as: + +Rename Y to X on right + +Algorithm: +---------- +DB-file left ---filename, Metadata(=:MD)---> DB-file right + /|\ | + | fileID, MD + fileID, MD | + | \|/ + X Y + +*/ + + +class FindDBAssoc +{ + /* + load and associate db-files by filename and metadata(size, date) + fileID, MD |-> fileID + */ +public: + struct AssocKey + { + AssocKey(const Utility::FileID& fileId, + const wxLongLong& lastWriteTimeRaw, + const wxULongLong& fileSize); + + bool operator<(const AssocKey& other) const; + + Utility::FileID fileId_; + wxLongLong lastWriteTimeRaw_; + wxULongLong fileSize_; + }; + + FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, + std::map<AssocKey, Utility::FileID>& assocDBLeftToRight); + +private: + void recurse(const DirContainer& leftSide, const DirContainer& rightSide); + + std::map<AssocKey, Utility::FileID>& assocDBLeftToRight_; //--> +}; + + +inline +FindDBAssoc::AssocKey::AssocKey(const Utility::FileID& fileId, + const wxLongLong& lastWriteTimeRaw, + const wxULongLong& fileSize) : + fileId_(fileId), + lastWriteTimeRaw_(lastWriteTimeRaw), + fileSize_(fileSize) {} + + +inline +bool FindDBAssoc::AssocKey::operator<(const AssocKey& other) const +{ + if (fileId_ != other.fileId_) + return fileId_ < other.fileId_; + + if (lastWriteTimeRaw_ != other.lastWriteTimeRaw_) + return lastWriteTimeRaw_ < other.lastWriteTimeRaw_; + + return fileSize_ < other.fileSize_; +} + + +FindDBAssoc::FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, + std::map<AssocKey, Utility::FileID>& assocDBLeftToRight) : assocDBLeftToRight_(assocDBLeftToRight) +{ + try + { + std::pair<FreeFileSync::DirInfoPtr, FreeFileSync::DirInfoPtr> dbInfo = + FreeFileSync::loadFromDisk(baseMapping); //throw (FileError) + + recurse(dbInfo.first->baseDirContainer, + dbInfo.second->baseDirContainer); + } + catch (...) {} //swallow... +} + + +void FindDBAssoc::recurse(const DirContainer& leftSide, const DirContainer& rightSide) +{ + for (DirContainer::SubFileList::const_iterator i = leftSide.getSubFiles().begin(); i != leftSide.getSubFiles().end(); ++i) + { + const FileDescriptor& fileDescrI = i->second.getData(); + if (!fileDescrI.fileIdentifier.isNull()) //fileIdentifier may be NULL + { + const DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(i->first); + + //find files that exist on left and right + if (j != rightSide.getSubFiles().end()) + { + const FileDescriptor& fileDescrJ = j->second.getData(); + if (!fileDescrJ.fileIdentifier.isNull()) //fileIdentifier may be NULL + { + if ( fileDescrI.lastWriteTimeRaw == fileDescrJ.lastWriteTimeRaw && + fileDescrI.fileSize == fileDescrJ.fileSize) + { + assocDBLeftToRight_[AssocKey(fileDescrI.fileIdentifier, + fileDescrI.lastWriteTimeRaw, + fileDescrI.fileSize)] = fileDescrJ.fileIdentifier; + } + } + } + } + } + +//----------------------------------------------------------------------------------------------- + for (DirContainer::SubDirList::const_iterator i = leftSide.getSubDirs().begin(); i != leftSide.getSubDirs().end(); ++i) + { + const DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(i->first); + + //directories that exist on both sides + if (j != rightSide.getSubDirs().end()) + { + recurse(i->second, j->second); //recurse into subdirectories + } + } +} + + + +class FindRenameCandidates +{ +public: + FindRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping) + { + FindDBAssoc(baseMapping, + assocDBLeftToRight); + + if (!assocDBLeftToRight.empty()) + recurse(baseMapping); + } + + void getRenameCandidates(std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnLeft, + std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnRight); + +private: + void recurse(HierarchyObject& hierObj) + { + //files + std::for_each(hierObj.subFiles.begin(), hierObj.subFiles.end(), + boost::bind(&FindRenameCandidates::processFile, this, _1)); + + //directories + std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), + boost::bind(&FindRenameCandidates::recurse, this, _1));//recursion + } + + void processFile(FileMapping& fileObj) + { + switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction + { + case SO_CREATE_NEW_LEFT: + if (!fileObj.getFileID<RIGHT_SIDE>().isNull()) //fileIdentifier may be NULL + createLeft[FindDBAssoc::AssocKey(fileObj.getFileID<RIGHT_SIDE>(), + fileObj.getLastWriteTime<RIGHT_SIDE>(), + fileObj.getFileSize<RIGHT_SIDE>())] = &fileObj; + break; + + case SO_CREATE_NEW_RIGHT: + if (!fileObj.getFileID<LEFT_SIDE>().isNull()) //fileIdentifier may be NULL + createRight.push_back(&fileObj); + break; + + case SO_DELETE_LEFT: + if (!fileObj.getFileID<LEFT_SIDE>().isNull()) //fileIdentifier may be NULL + deleteLeft.push_back(&fileObj); + break; + + case SO_DELETE_RIGHT: + if (!fileObj.getFileID<RIGHT_SIDE>().isNull()) //fileIdentifier may be NULL + deleteRight[FindDBAssoc::AssocKey(fileObj.getFileID<RIGHT_SIDE>(), + fileObj.getLastWriteTime<RIGHT_SIDE>(), + fileObj.getFileSize<RIGHT_SIDE>())] = &fileObj; + break; + + case SO_OVERWRITE_RIGHT: + case SO_OVERWRITE_LEFT: + case SO_DO_NOTHING: + case SO_UNRESOLVED_CONFLICT: + break; + } + + } + + + std::vector<FileMapping*> createRight; //pointer always bound! + std::vector<FileMapping*> deleteLeft; // +// | +// \|/ + std::map<FindDBAssoc::AssocKey, Utility::FileID> assocDBLeftToRight; +// | +// \|/ + std::map<FindDBAssoc::AssocKey, FileMapping*> deleteRight; //pointer always bound! + std::map<FindDBAssoc::AssocKey, FileMapping*> createLeft; // + +}; + + + +void FindRenameCandidates::getRenameCandidates( + std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnLeft, + std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnRight) +{ + for (std::vector<FileMapping*>::const_iterator crRightIter = createRight.begin(); + crRightIter != createRight.end(); + ++crRightIter) + { + const FindDBAssoc::AssocKey assocDbKey((*crRightIter)->getFileID<LEFT_SIDE>(), + (*crRightIter)->getLastWriteTime<LEFT_SIDE>(), + (*crRightIter)->getFileSize<LEFT_SIDE>()); + + const std::map<FindDBAssoc::AssocKey, Utility::FileID>::const_iterator assocDBIter = + assocDBLeftToRight.find(assocDbKey); + + if (assocDBIter != assocDBLeftToRight.end()) + { + std::map<FindDBAssoc::AssocKey, FileMapping*>::const_iterator delRightIter = + deleteRight.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side + assocDbKey.lastWriteTimeRaw_, + assocDbKey.fileSize_)); + + if (delRightIter != deleteRight.end()) + { + renameOnRight.push_back(std::make_pair(*crRightIter, delRightIter->second)); + } + } + } + //------------------------------------------------------------------------------------------------ + for (std::vector<FileMapping*>::const_iterator delLeftIter = deleteLeft.begin(); + delLeftIter != deleteLeft.end(); + ++delLeftIter) + { + const FindDBAssoc::AssocKey assocDbKey((*delLeftIter)->getFileID<LEFT_SIDE>(), + (*delLeftIter)->getLastWriteTime<LEFT_SIDE>(), + (*delLeftIter)->getFileSize<LEFT_SIDE>()); + + const std::map<FindDBAssoc::AssocKey, Utility::FileID>::const_iterator assocDBIter = + assocDBLeftToRight.find(assocDbKey); + + if (assocDBIter != assocDBLeftToRight.end()) + { + std::map<FindDBAssoc::AssocKey, FileMapping*>::const_iterator createLeftIter = + createLeft.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side + assocDbKey.lastWriteTimeRaw_, + assocDbKey.fileSize_)); + + if (createLeftIter != createLeft.end()) + { + renameOnLeft.push_back(std::make_pair(createLeftIter->second, *delLeftIter)); + } + } + } +} + + +void FreeFileSync::getRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping, //in + std::vector<std::pair<CreateOnLeft, DeleteOnLeft> >& renameOnLeft, //out + std::vector<std::pair<CreateOnRight, DeleteOnRight> >& renameOnRight) //out throw()! +{ + FindRenameCandidates(baseMapping).getRenameCandidates(renameOnLeft, renameOnRight); +} + diff --git a/library/detectRenaming.h b/library/detectRenaming.h new file mode 100644 index 00000000..82cb543e --- /dev/null +++ b/library/detectRenaming.h @@ -0,0 +1,20 @@ +#ifndef DETECTRENAMING_H_INCLUDED +#define DETECTRENAMING_H_INCLUDED + +#include "../fileHierarchy.h" + + +//identify a file "create and delete"-operation as a file renaming! + +namespace FreeFileSync +{ +typedef FileMapping* CreateOnLeft; +typedef FileMapping* DeleteOnLeft; +typedef FileMapping* CreateOnRight; +typedef FileMapping* DeleteOnRight; +void getRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping, //in + std::vector<std::pair<CreateOnLeft, DeleteOnLeft> >& renameOnLeft, //out + std::vector<std::pair<CreateOnRight, DeleteOnRight> >& renameOnRight); //out throw()! +} + +#endif // DETECTRENAMING_H_INCLUDED diff --git a/library/filter.cpp b/library/filter.cpp index 6565da2e..25877513 100644 --- a/library/filter.cpp +++ b/library/filter.cpp @@ -10,24 +10,24 @@ #include "../shared/loki/LokiTypeInfo.h" #include "../shared/serialize.h" -using FreeFileSync::FilterProcess; +using FreeFileSync::BaseFilter; using FreeFileSync::NameFilter; //-------------------------------------------------------------------------------------------------- -bool FilterProcess::operator==(const FilterProcess& other) const +bool BaseFilter::operator==(const BaseFilter& other) const { return !(*this < other) && !(other < *this); } -bool FilterProcess::operator!=(const FilterProcess& other) const +bool BaseFilter::operator!=(const BaseFilter& other) const { return !(*this == other); } -bool FilterProcess::operator<(const FilterProcess& other) const +bool BaseFilter::operator<(const BaseFilter& other) const { if (Loki::TypeInfo(typeid(*this)) != typeid(other)) return Loki::TypeInfo(typeid(*this)) < typeid(other); @@ -37,7 +37,7 @@ bool FilterProcess::operator<(const FilterProcess& other) const } -void FilterProcess::saveFilter(wxOutputStream& stream) const //serialize derived object +void BaseFilter::saveFilter(wxOutputStream& stream) const //serialize derived object { //save type information Utility::writeString(stream, uniqueClassIdentifier()); @@ -47,7 +47,7 @@ void FilterProcess::saveFilter(wxOutputStream& stream) const //serialize derived } -FilterProcess::FilterRef FilterProcess::loadFilter(wxInputStream& stream) +BaseFilter::FilterRef BaseFilter::loadFilter(wxInputStream& stream) { //read type information const Zstring uniqueClassId = Utility::readString(stream); @@ -72,7 +72,7 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st #ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case - filterFormatted.MakeLower(); + filterFormatted.MakeUpper(); #elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case: nothing to do here #endif @@ -140,7 +140,7 @@ bool matchesFilter(const DefaultChar* name, const std::set<Zstring>& filter) { #ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case Zstring nameFormatted = name; - nameFormatted.MakeLower(); + nameFormatted.MakeUpper(); #elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case const DefaultChar* const nameFormatted = name; //nothing to do here #endif @@ -180,7 +180,7 @@ bool matchesFilterBegin(const DefaultChar* name, const std::set<Zstring>& filter { #ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case Zstring nameFormatted = name; - nameFormatted.MakeLower(); + nameFormatted.MakeUpper(); #elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case const DefaultChar* const nameFormatted = name; //nothing to do here #endif @@ -265,7 +265,7 @@ bool NameFilter::isNull() const } -bool NameFilter::cmpLessSameType(const FilterProcess& other) const +bool NameFilter::cmpLessSameType(const BaseFilter& other) const { //typeid(*this) == typeid(other) in this context! assert(typeid(*this) == typeid(other)); @@ -300,7 +300,7 @@ void NameFilter::save(wxOutputStream& stream) const } -FilterProcess::FilterRef NameFilter::load(wxInputStream& stream) //"constructor" +BaseFilter::FilterRef NameFilter::load(wxInputStream& stream) //"constructor" { const Zstring include = Utility::readString(stream); const Zstring exclude = Utility::readString(stream); diff --git a/library/filter.h b/library/filter.h index efdb01fd..ea725291 100644 --- a/library/filter.h +++ b/library/filter.h @@ -11,17 +11,23 @@ namespace FreeFileSync //------------------------------------------------------------------ /* class hierarchy: - FilterProcess (interface) + BaseFilter (interface) /|\ _________|_____________ | | | NullFilter NameFilter CombinedFilter */ -class FilterProcess //interface for filtering +/* +Semantics of BaseFilter: +1. using it creates a NEW folder hierarchy! -> must be respected by <Automatic>-mode! +2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder! +*/ + +class BaseFilter //interface for filtering { public: - virtual ~FilterProcess() {} + virtual ~BaseFilter() {} //filtering virtual bool passFileFilter(const DefaultChar* relFilename) const = 0; @@ -32,11 +38,11 @@ public: virtual bool isNull() const = 0; //filter is equivalent to NullFilter, but may be technically slower //comparison - bool operator<(const FilterProcess& other) const; - bool operator==(const FilterProcess& other) const; - bool operator!=(const FilterProcess& other) const; + bool operator<(const BaseFilter& other) const; + bool operator==(const BaseFilter& other) const; + bool operator!=(const BaseFilter& other) const; - typedef boost::shared_ptr<const FilterProcess> FilterRef; //always bound by design! + typedef boost::shared_ptr<const BaseFilter> FilterRef; //always bound by design! //serialization void saveFilter(wxOutputStream& stream) const; //serialize derived object @@ -45,11 +51,11 @@ public: private: virtual Zstring uniqueClassIdentifier() const = 0; //get identifier, used for serialization virtual void save(wxOutputStream& stream) const = 0; //serialization - virtual bool cmpLessSameType(const FilterProcess& other) const = 0; //typeid(*this) == typeid(other) in this context! + virtual bool cmpLessSameType(const BaseFilter& other) const = 0; //typeid(*this) == typeid(other) in this context! }; -class NullFilter : public FilterProcess //no filtering at all +class NullFilter : public BaseFilter //no filtering at all { public: static FilterRef load(wxInputStream& stream); //"serial constructor" @@ -60,11 +66,11 @@ public: private: virtual Zstring uniqueClassIdentifier() const; virtual void save(wxOutputStream& stream) const {} - virtual bool cmpLessSameType(const FilterProcess& other) const; + virtual bool cmpLessSameType(const BaseFilter& other) const; }; -class NameFilter : public FilterProcess //standard filter by filename +class NameFilter : public BaseFilter //standard filter by filename { public: NameFilter(const Zstring& includeFilter, const Zstring& excludeFilter); @@ -77,7 +83,7 @@ public: private: virtual Zstring uniqueClassIdentifier() const; virtual void save(wxOutputStream& stream) const; - virtual bool cmpLessSameType(const FilterProcess& other) const; + virtual bool cmpLessSameType(const BaseFilter& other) const; std::set<Zstring> filterFileIn; std::set<Zstring> filterFolderIn; @@ -89,7 +95,7 @@ private: }; -class CombinedFilter : public FilterProcess //combine two filters to match if and only if both match +class CombinedFilter : public BaseFilter //combine two filters to match if and only if both match { public: CombinedFilter(const FilterRef& first, const FilterRef& second) : first_(first), second_(second) {} @@ -102,7 +108,7 @@ public: private: virtual Zstring uniqueClassIdentifier() const; virtual void save(wxOutputStream& stream) const; - virtual bool cmpLessSameType(const FilterProcess& other) const; + virtual bool cmpLessSameType(const BaseFilter& other) const; const FilterRef first_; const FilterRef second_; @@ -110,8 +116,8 @@ private: //small helper method: remove Null-filters -FilterProcess::FilterRef combineFilters(const FilterProcess::FilterRef& first, - const FilterProcess::FilterRef& second); +BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first, + const BaseFilter::FilterRef& second); @@ -132,7 +138,7 @@ FilterProcess::FilterRef combineFilters(const FilterProcess::FilterRef& first, //---------------Inline Implementation--------------------------------------------------- inline -FilterProcess::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor" +BaseFilter::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor" { return FilterRef(new NullFilter); } @@ -161,7 +167,7 @@ bool NullFilter::isNull() const inline -bool NullFilter::cmpLessSameType(const FilterProcess& other) const +bool NullFilter::cmpLessSameType(const BaseFilter& other) const { //typeid(*this) == typeid(other) in this context! assert(typeid(*this) == typeid(other)); @@ -200,7 +206,7 @@ bool CombinedFilter::isNull() const inline -bool CombinedFilter::cmpLessSameType(const FilterProcess& other) const +bool CombinedFilter::cmpLessSameType(const BaseFilter& other) const { //typeid(*this) == typeid(other) in this context! assert(typeid(*this) == typeid(other)); @@ -229,7 +235,7 @@ void CombinedFilter::save(wxOutputStream& stream) const inline -FilterProcess::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor" +BaseFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor" { FilterRef first = loadFilter(stream); FilterRef second = loadFilter(stream); @@ -239,13 +245,13 @@ FilterProcess::FilterRef CombinedFilter::load(wxInputStream& stream) //"construc inline -FilterProcess::FilterRef combineFilters(const FilterProcess::FilterRef& first, - const FilterProcess::FilterRef& second) +BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first, + const BaseFilter::FilterRef& second) { if (first->isNull()) { if (second->isNull()) - return FilterProcess::FilterRef(new NullFilter); + return BaseFilter::FilterRef(new NullFilter); else return second; } @@ -254,7 +260,7 @@ FilterProcess::FilterRef combineFilters(const FilterProcess::FilterRef& first, if (second->isNull()) return first; else - return FilterProcess::FilterRef(new CombinedFilter(first, second)); + return BaseFilter::FilterRef(new CombinedFilter(first, second)); } } diff --git a/library/iconBuffer.cpp b/library/iconBuffer.cpp index d386c85a..21f85372 100644 --- a/library/iconBuffer.cpp +++ b/library/iconBuffer.cpp @@ -7,10 +7,82 @@ #include <map> #include <queue> #include <stdexcept> +#include <set> using FreeFileSync::IconBuffer; +const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be sufficient... +{ + static wxIcon folderIcon; + + static bool isInitalized = false; + if (!isInitalized) + { + isInitalized = true; + + SHFILEINFO fileInfo; + fileInfo.hIcon = 0; //initialize hIcon + + //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup! + if (::SHGetFileInfo(DefaultStr("dummy"), //Windows Seven doesn't like this parameter to be an empty string + FILE_ATTRIBUTE_DIRECTORY, + &fileInfo, + sizeof(fileInfo), + SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES) && + + fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! + { + folderIcon.SetHICON(fileInfo.hIcon); + folderIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); + } + } + return folderIcon; +} + +namespace +{ +Zstring getFileExtension(const Zstring& filename) +{ + const Zstring shortName = filename.AfterLast(DefaultChar('\\')); //Zstring::AfterLast() returns the whole string if ch not found + const size_t pos = shortName.Find(DefaultChar('.'), true); + return pos == Zstring::npos ? + Zstring() : + Zstring(shortName.c_str() + pos + 1); +} + + +struct CmpFilenameWin +{ + bool operator()(const Zstring& a, const Zstring& b) const + { + return a.CmpNoCase(b) < 0; + } +}; + + +//test for extension for icons that physically have to be retrieved from disc +bool isPriceyExtension(const Zstring& extension) +{ + static std::set<Zstring, CmpFilenameWin> exceptions; + static bool isInitalized = false; + if (!isInitalized) + { + isInitalized = true; + exceptions.insert(DefaultStr("exe")); + exceptions.insert(DefaultStr("lnk")); + exceptions.insert(DefaultStr("ico")); + exceptions.insert(DefaultStr("ani")); + exceptions.insert(DefaultStr("cur")); + exceptions.insert(DefaultStr("url")); + exceptions.insert(DefaultStr("msc")); + exceptions.insert(DefaultStr("scr")); + } + return exceptions.find(extension) != exceptions.end(); +} +} +//################################################################################################################################################ + typedef std::vector<DefaultChar> BasicString; //simple thread safe string class: std::vector is guaranteed to not use reference counting, Effective STL, item 13 @@ -112,7 +184,7 @@ wxThread::ExitCode WorkerThread::Entry() if (threadExitIsRequested) //no mutex here: atomicity is not prob for a bool, but visibility (e.g. caching in registers) return 0; //shouldn't be a problem nevertheless because of implicit memory barrier caused by mutex.Lock() in .Wait() - //do work: get the file icon. + //do work: get the file icons doWork(); } } @@ -139,29 +211,25 @@ void WorkerThread::doWork() workload.pop_back(); } - if (iconBuffer->requestIcon(Zstring(&fileName[0]))) //thread safety: Zstring okay, won't be reference-counted in requestIcon(), fileName is NOT empty - break; //icon already in buffer: enter waiting state + if (iconBuffer->requestFileIcon(Zstring(&fileName[0]))) //thread safety: Zstring okay, won't be reference-counted in requestIcon(), fileName is NOT empty + continue; //icon already in buffer: skip //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName" - const unsigned int MAX_SIZE = 10000; - DefaultChar fullName[MAX_SIZE]; - const DWORD rv = ::GetFullPathName( - &fileName[0], //__in LPCTSTR lpFileName, - MAX_SIZE, //__in DWORD nBufferLength, - fullName, //__out LPTSTR lpBuffer, - NULL); //__out LPTSTR *lpFilePart - if (rv < MAX_SIZE && rv != 0) - { - //load icon - SHFILEINFO fileInfo; - fileInfo.hIcon = 0; //initialize hIcon + //but no problem, directory formatting takes care that filenames are always absolute! - if (::SHGetFileInfo(fullName, //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup! + //load icon + SHFILEINFO fileInfo; + fileInfo.hIcon = 0; //initialize hIcon + + const Zstring extension = getFileExtension(&fileName[0]); //thread-safe: no sharing! + if (isPriceyExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension + { + //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup! + if (::SHGetFileInfo(&fileName[0], //FreeFileSync::removeLongPathPrefix(&fileName[0]), //::SHGetFileInfo() can't handle \\?\-prefix! 0, &fileInfo, sizeof(fileInfo), SHGFI_ICON | SHGFI_SMALLICON) && - fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! { //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080 @@ -170,7 +238,8 @@ void WorkerThread::doWork() newIcon.SetHICON(fileInfo.hIcon); newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); - iconBuffer->insertIntoBuffer(&fileName[0], newIcon); //thread safety: icon may be deleted only within insertIntoBuffer() + iconBuffer->insertIntoBuffer(&fileName[0], newIcon); //thread safety: icon buffer is written by this thread and this call only, so + //newIcon can safely go out of scope without race-condition because of ref-counting //freeing of icon handle seems to happen somewhere beyond wxIcon destructor //if (!DestroyIcon(fileInfo.hIcon)) @@ -178,16 +247,32 @@ void WorkerThread::doWork() continue; } } + else //no read-access to disk! determine icon by extension + { + if (::SHGetFileInfo((Zstring(DefaultStr("dummy.")) + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name + FILE_ATTRIBUTE_NORMAL, + &fileInfo, + sizeof(fileInfo), + SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES) && + fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! + { + wxIcon newIcon; //attention: wxIcon uses reference counting! + newIcon.SetHICON(fileInfo.hIcon); + newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); + + iconBuffer->insertIntoBuffer(extension.c_str(), newIcon); //thread safety: icon buffer is written by this thread and this call only, so + continue; + } + } + //if loading of icon fails for whatever reason, just save a dummy icon to avoid re-loading iconBuffer->insertIntoBuffer(&fileName[0], wxNullIcon); } } //--------------------------------------------------------------------------------------------------- - -typedef Zstring FileName; -class IconDB : public std::map<FileName, wxIcon> {}; -class IconDbSequence : public std::queue<FileName> {}; +class IconDB : public std::map<Zstring, wxIcon> {}; // entryName/icon +class IconDbSequence : public std::queue<Zstring> {}; // entryName //--------------------------------------------------------------------------------------------------- @@ -213,11 +298,16 @@ IconBuffer::~IconBuffer() } -bool IconBuffer::requestIcon(const Zstring& fileName, wxIcon* icon) +bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon) { + const Zstring extension = getFileExtension(fileName); + wxCriticalSectionLocker dummy(*lockIconDB); - IconDB::const_iterator i = buffer->find(fileName); + IconDB::const_iterator i = buffer->find( //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension + isPriceyExtension(extension) ? + fileName : + extension); if (i != buffer->end()) { if (icon != NULL) @@ -235,13 +325,13 @@ void IconBuffer::setWorkload(const std::vector<Zstring>& load) } -void IconBuffer::insertIntoBuffer(const DefaultChar* fileName, const wxIcon& icon) //called by worker thread +void IconBuffer::insertIntoBuffer(const DefaultChar* entryName, const wxIcon& icon) //called by worker thread { if (icon.IsOk()) //this check won't hurt { wxCriticalSectionLocker dummy(*lockIconDB); - const Zstring fileNameZ = fileName; + const Zstring fileNameZ = entryName; const std::pair<IconDB::iterator, bool> rc = buffer->insert(IconDB::value_type(fileNameZ, icon)); @@ -260,3 +350,6 @@ void IconBuffer::insertIntoBuffer(const DefaultChar* fileName, const wxIcon& ico } } + + + diff --git a/library/iconBuffer.h b/library/iconBuffer.h index e6d2bcaf..703f7eb7 100644 --- a/library/iconBuffer.h +++ b/library/iconBuffer.h @@ -25,10 +25,12 @@ class IconBuffer public: static IconBuffer& getInstance(); - bool requestIcon(const Zstring& fileName, wxIcon* icon = NULL); //returns false if icon is not in buffer + static const wxIcon& getDirectoryIcon(); //one folder icon should be sufficient... + + bool requestFileIcon(const Zstring& fileName, wxIcon* icon = NULL); //returns false if icon is not in buffer void setWorkload(const std::vector<Zstring>& load); //(re-)set new workload of icons to be retrieved; - static const int ICON_SIZE = 16; //size in pixel + static const int ICON_SIZE = 16; //size in pixel static const size_t BUFFER_SIZE = 800; //maximum number if icons to buffer private: @@ -36,7 +38,7 @@ private: ~IconBuffer(); //methods used by worker thread - void insertIntoBuffer(const DefaultChar* fileName, const wxIcon& icon); + void insertIntoBuffer(const DefaultChar* entryName, const wxIcon& icon); //---------------------- Shared Data ------------------------- std::auto_ptr<wxCriticalSection> lockIconDB; diff --git a/library/processXml.cpp b/library/processXml.cpp index af16f91e..4773fb72 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -416,6 +416,9 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg //last update check readXmlElementLogging("LastCheckForUpdates", global, outputCfg.lastUpdateCheck); + //minimum size (in bytes) for files to be considered for rename-detection + readXmlElementLogging("DetectRenameThreshold", global, outputCfg.detectRenameThreshold); + const TiXmlElement* optionalDialogs = TiXmlHandleConst(root).FirstChild("Shared").FirstChild("ShowOptionalDialogs").ToElement(); @@ -814,6 +817,9 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD //last update check addXmlElement("LastCheckForUpdates", inputCfg.lastUpdateCheck, global); + //minimum size (in bytes) for files to be considered for rename-detection + addXmlElement("DetectRenameThreshold", inputCfg.detectRenameThreshold, global); + //optional dialogs TiXmlElement* optionalDialogs = new TiXmlElement("ShowOptionalDialogs"); diff --git a/library/processXml.h b/library/processXml.h index 80db71a3..9cb920d9 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -109,12 +109,15 @@ struct XmlGlobalSettings programLanguage(retrieveSystemLanguage()), ignoreOneHourDiff(false), copyLockedFiles(true), - lastUpdateCheck(0) {} + detectRenameThreshold(1024 *1024), + lastUpdateCheck(0) + {} int programLanguage; - bool ignoreOneHourDiff; //ignore +/- 1 hour due to DST change - bool copyLockedFiles; //VSS usage - long lastUpdateCheck; //time of last update check + bool ignoreOneHourDiff; //ignore +/- 1 hour due to DST change + bool copyLockedFiles; //VSS usage + unsigned int detectRenameThreshold; //minimum size (in bytes) for files to be considered for rename-detection + long lastUpdateCheck; //time of last update check OptionalDialogs optDialogs; diff --git a/library/resources.cpp b/library/resources.cpp index 02f5d701..3b44a361 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -21,164 +21,6 @@ const GlobalResources& GlobalResources::getInstance() GlobalResources::GlobalResources() { - //map, allocate and initialize pictures - bitmapResource[wxT("CmpByTime.png")] = (bitmapCmpByTime = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("CmpByContent.png")] = (bitmapCmpByContent = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("left arrow.png")] = (bitmapArrowLeft = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("right arrow.png")] = (bitmapArrowRight = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("left arrow create.png")] = (bitmapArrowLeftCr = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("right arrow create.png")] = (bitmapArrowRightCr = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("no arrow.png")] = (bitmapArrowNone = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("start sync.png")] = (bitmapStartSync = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("start sync dis.png")] = (bitmapStartSyncDis = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("left delete.png")] = (bitmapDeleteLeft = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("right delete.png")] = (bitmapDeleteRight = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("email.png")] = (bitmapEmail = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("about.png")] = (bitmapAbout = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("about_small.png")] = (bitmapAboutSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("website.png")] = (bitmapWebsite = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("exit.png")] = (bitmapExit = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("compare.png")] = (bitmapCompare = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("compare disabled.png")] = (bitmapCompareDisabled = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("sync.png")] = (bitmapSync = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("sync disabled.png")] = (bitmapSyncDisabled = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("swap.png")] = (bitmapSwap = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("swap_slim.png")] = (bitmapSwapSlim = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("help.png")] = (bitmapHelp = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftOnly.png")] = (bitmapLeftOnly = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftOnlyAct.png")] = (bitmapLeftOnlyAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftOnlyDeact.png")] = (bitmapLeftOnlyDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftNewer.png")] = (bitmapLeftNewer = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftNewerAct.png")] = (bitmapLeftNewerAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftNewerDeact.png")] = (bitmapLeftNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightNewer.png")] = (bitmapRightNewer = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightNewerAct.png")] = (bitmapRightNewerAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightNewerDeact.png")] = (bitmapRightNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("conflict.png")] = (bitmapConflict = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("conflictGrey.png")] = (bitmapConflictGrey = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("conflictAct.png")] = (bitmapConflictAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("conflictDeact.png")] = (bitmapConflictDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("include.png")] = (bitmapInclude = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("exclude.png")] = (bitmapExclude = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("filter active.png")] = (bitmapFilterOn = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("filter not active.png")] = (bitmapFilterOff = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("filter_small.png")] = (bitmapFilterSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("filterSmallGrey.png")] = (bitmapFilterSmallGrey = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("warning.png")] = (bitmapWarning = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("warningSmall.png")] = (bitmapWarningSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("error.png")] = (bitmapError = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("small arrow up.png"]) = (bitmapSmallUp = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("small arrow down.png")] = (bitmapSmallDown = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("save.png")] = (bitmapSave = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("load.png")] = (bitmapLoad = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("saveSmall.png")] = (bitmapSaveSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("loadSmall.png")] = (bitmapLoadSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("newSmall.png")] = (bitmapNewSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("FreeFileSync.png")] = (bitmapFFS = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("deleteFile.png")] = (bitmapDeleteFile = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("gpl.png")] = (bitmapGPL = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusPause.png")] = (bitmapStatusPause = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusError.png")] = (bitmapStatusError = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusSuccess.png")] = (bitmapStatusSuccess = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusWarning.png")] = (bitmapStatusWarning = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusScanning.png")] = (bitmapStatusScanning = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusBinaryCompare.png")]= (bitmapStatusBinCompare = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusSyncing.png")] = (bitmapStatusSyncing = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("logo.png")] = (bitmapLogo = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusEdge.png")] = (bitmapStatusEdge = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("add pair.png")] = (bitmapAddFolderPair = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("remove pair.png")] = (bitmapRemoveFolderPair = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("remove pair disabl.png")] = (bitmapRemoveFolderPairD = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("link.png")] = (bitmapLink = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("background.png")] = (bitmapBackground = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("compare_small.png")] = (bitmapCompareSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("sync_small.png")] = (bitmapSyncSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("clock_small.png")] = (bitmapClockSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("clock.png")] = (bitmapClock = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("batch.png")] = (bitmapBatch = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("batch_small.png")] = (bitmapBatchSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("move up.png")] = (bitmapMoveUp = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("move down.png")] = (bitmapMoveDown = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox_true.png")] = (bitmapCheckBoxTrue = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox_true_focus.png")] = (bitmapCheckBoxTrueFocus = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox_false.png")] = (bitmapCheckBoxFalse = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox_false_focus.png")] = (bitmapCheckBoxFalseFocus = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("settings.png")] = (bitmapSettings = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("settings_small.png")] = (bitmapSettingsSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("recycler.png")] = (bitmapRecycler = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("shift.png")] = (bitmapShift = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncConfig.png")] = (bitmapSyncCfg = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncConfigSmall.png")] = (bitmapSyncCfgSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncConfigSmallGrey.png")] = (bitmapSyncCfgSmallGrey = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("cmpConfig.png")] = (bitmapCmpCfg = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncPreview.png")] = (bitmapPreview = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncPreviewDisabl.png")] = (bitmapPreviewDisabled = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("question.png")] = (bitmapQuestion = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("czechRep.png")] = (bitmapCzechRep = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("china.png")] = (bitmapChina = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("holland.png")] = (bitmapHolland = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("england.png")] = (bitmapEngland = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("france.png")] = (bitmapFrance = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("finland.png")] = (bitmapFinland = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("germany.png")] = (bitmapGermany = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("hungary.png")] = (bitmapHungary = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("romania.png")] = (bitmapRomania = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("taiwan.png")] = (bitmapTaiwan = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("turkey.png")] = (bitmapTurkey = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("italy.png")] = (bitmapItaly = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("japan.png")] = (bitmapJapan = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("poland.png")] = (bitmapPoland = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("portugal.png")] = (bitmapPortugal = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("brazil.png")] = (bitmapBrazil = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("slovakia.png")] = (bitmapSlovakia = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("spain.png")] = (bitmapSpain = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("russia.png")] = (bitmapRussia = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncCreateLeftAct.png")] = (bitmapSyncCreateLeftAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncCreateLeftDeact.png")] = (bitmapSyncCreateLeftDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncCreateRightAct.png")] = (bitmapSyncCreateRightAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncCreateRightDeact.png")] = (bitmapSyncCreateRightDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDeleteLeftAct.png")] = (bitmapSyncDeleteLeftAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDeleteLeftDeact.png")] = (bitmapSyncDeleteLeftDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDeleteRightAct.png")] = (bitmapSyncDeleteRightAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDeleteRightDeact.png")] = (bitmapSyncDeleteRightDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirLeftAct.png")] = (bitmapSyncDirLeftAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirLeftDeact.png")] = (bitmapSyncDirLeftDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirRightAct.png")] = (bitmapSyncDirRightAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirRightDeact.png")] = (bitmapSyncDirRightDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirNoneAct.png")] = (bitmapSyncDirNoneAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirNoneDeact.png")] = (bitmapSyncDirNoneDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirLeftSmall.png")] = (bitmapSyncDirLeftSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirRightSmall.png")] = (bitmapSyncDirRightSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncDirNoneSmall.png")] = (bitmapSyncDirNoneSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("createLeftSmall.png")] = (bitmapCreateLeftSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("createRightSmall.png")] = (bitmapCreateRightSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("deleteLeftSmall.png")] = (bitmapDeleteLeftSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("deleteRightSmall.png")] = (bitmapDeleteRightSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftOnlySmall.png")] = (bitmapLeftOnlySmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlySmall.png")] = (bitmapRightOnlySmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("leftNewerSmall.png")] = (bitmapLeftNewerSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightNewerSmall.png")] = (bitmapRightNewerSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalSmall.png")] = (bitmapEqualSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentSmall.png")] = (bitmapDifferentSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("conflictSmall.png")] = (bitmapConflictSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("create.png")] = (bitmapCreate = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("update.png")] = (bitmapUpdate = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("delete.png")] = (bitmapDelete = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("data.png")] = (bitmapData = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("cmpViewSmall.png")] = (bitmapCmpViewSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("syncViewSmall.png")] = (bitmapSyncViewSmall = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("toggleViewSmall.png")] = (bitmapSwitchViewSmall = new wxBitmap(wxNullBitmap)); - - //init all the other resource files animationMoney = new wxAnimation(wxNullAnimation); animationSync = new wxAnimation(wxNullAnimation); @@ -227,7 +69,6 @@ void GlobalResources::load() const wxZipInputStream resourceFile(input); - std::map<wxString, wxBitmap*>::iterator bmp; while (true) { std::auto_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); @@ -236,9 +77,12 @@ void GlobalResources::load() const const wxString name = entry->GetName(); - //search if entry is available in map - if ((bmp = bitmapResource.find(name)) != bitmapResource.end()) - *(bmp->second) = wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + //generic image loading + if (name.EndsWith(wxT(".png"))) + { + if (bitmapResource.find(name) == bitmapResource.end()) //avoid duplicate entry: prevent memory leak! + bitmapResource[name] = new wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + } else if (name == wxT("money.gif")) loadAnimFromZip(resourceFile, animationMoney); else if (name == wxT("working.gif")) @@ -253,15 +97,18 @@ void GlobalResources::load() const //#include "FreeFileSync.xpm" //*programIcon = wxIcon(FreeFileSync_xpm); - //use big FFS logo bitmap for better quality - programIcon->CopyFromBitmap(*bitmapFFS); + //use big logo bitmap for better quality + programIcon->CopyFromBitmap(getImageByName(wxT("FreeFileSync.png"))); #endif } const wxBitmap& GlobalResources::getImageByName(const wxString& imageName) const { - std::map<wxString, wxBitmap*>::const_iterator bmp = bitmapResource.find(imageName); + const std::map<wxString, wxBitmap*>::const_iterator bmp = imageName.Find(wxChar('.')) == wxNOT_FOUND ? //assume .png ending if nothing else specified + bitmapResource.find(imageName + wxT(".png")) : + bitmapResource.find(imageName); + if (bmp != bitmapResource.end()) return *bmp->second; else diff --git a/library/resources.h b/library/resources.h index 512d7ed9..c6424dbb 100644 --- a/library/resources.h +++ b/library/resources.h @@ -14,166 +14,9 @@ public: const wxBitmap& getImageByName(const wxString& imageName) const; - //image resource objects - wxBitmap* bitmapCmpByTime; - wxBitmap* bitmapCmpByContent; - wxBitmap* bitmapArrowLeft; - wxBitmap* bitmapArrowRight; - wxBitmap* bitmapArrowLeftCr; - wxBitmap* bitmapArrowRightCr; - wxBitmap* bitmapArrowNone; - wxBitmap* bitmapStartSync; - wxBitmap* bitmapStartSyncDis; - wxBitmap* bitmapDeleteLeft; - wxBitmap* bitmapDeleteRight; - wxBitmap* bitmapEmail; - wxBitmap* bitmapAbout; - wxBitmap* bitmapAboutSmall; - wxBitmap* bitmapWebsite; - wxBitmap* bitmapExit; - wxBitmap* bitmapCompare; - wxBitmap* bitmapCompareDisabled; - wxBitmap* bitmapSync; - wxBitmap* bitmapSyncDisabled; - wxBitmap* bitmapSwap; - wxBitmap* bitmapSwapSlim; - wxBitmap* bitmapHelp; - wxBitmap* bitmapLeftOnly; - wxBitmap* bitmapLeftOnlyAct; - wxBitmap* bitmapLeftOnlyDeact; - wxBitmap* bitmapRightOnly; - wxBitmap* bitmapRightOnlyAct; - wxBitmap* bitmapRightOnlyDeact; - wxBitmap* bitmapLeftNewer; - wxBitmap* bitmapLeftNewerAct; - wxBitmap* bitmapLeftNewerDeact; - wxBitmap* bitmapRightNewer; - wxBitmap* bitmapRightNewerAct; - wxBitmap* bitmapRightNewerDeact; - wxBitmap* bitmapEqual; - wxBitmap* bitmapEqualAct; - wxBitmap* bitmapEqualDeact; - wxBitmap* bitmapDifferent; - wxBitmap* bitmapDifferentAct; - wxBitmap* bitmapDifferentDeact; - wxBitmap* bitmapConflict; - wxBitmap* bitmapConflictGrey; - wxBitmap* bitmapConflictAct; - wxBitmap* bitmapConflictDeact; - wxBitmap* bitmapInclude; - wxBitmap* bitmapExclude; - wxBitmap* bitmapFilterOn; - wxBitmap* bitmapFilterOff; - wxBitmap* bitmapFilterSmall; - wxBitmap* bitmapFilterSmallGrey; - wxBitmap* bitmapWarning; - wxBitmap* bitmapWarningSmall; - wxBitmap* bitmapError; - wxBitmap* bitmapSmallUp; - wxBitmap* bitmapSmallDown; - wxBitmap* bitmapSave; - wxBitmap* bitmapLoad; - wxBitmap* bitmapSaveSmall; - wxBitmap* bitmapLoadSmall; - wxBitmap* bitmapNewSmall; - wxBitmap* bitmapFFS; - wxBitmap* bitmapDeleteFile; - wxBitmap* bitmapGPL; - wxBitmap* bitmapStatusPause; - wxBitmap* bitmapStatusError; - wxBitmap* bitmapStatusSuccess; - wxBitmap* bitmapStatusWarning; - wxBitmap* bitmapStatusScanning; - wxBitmap* bitmapStatusBinCompare; - wxBitmap* bitmapStatusSyncing; - wxBitmap* bitmapLogo; - wxBitmap* bitmapStatusEdge; - wxBitmap* bitmapAddFolderPair; - wxBitmap* bitmapRemoveFolderPair; - wxBitmap* bitmapRemoveFolderPairD; - wxBitmap* bitmapLink; - wxBitmap* bitmapBackground; - wxBitmap* bitmapCompareSmall; - wxBitmap* bitmapSyncSmall; - wxBitmap* bitmapClockSmall; - wxBitmap* bitmapClock; - wxBitmap* bitmapBatch; - wxBitmap* bitmapBatchSmall; - wxBitmap* bitmapMoveUp; - wxBitmap* bitmapMoveDown; - wxBitmap* bitmapCheckBoxTrue; - wxBitmap* bitmapCheckBoxTrueFocus; - wxBitmap* bitmapCheckBoxFalse; - wxBitmap* bitmapCheckBoxFalseFocus; - wxBitmap* bitmapSettings; - wxBitmap* bitmapSettingsSmall; - wxBitmap* bitmapRecycler; - wxBitmap* bitmapShift; - wxBitmap* bitmapSyncCfg; - wxBitmap* bitmapSyncCfgSmall; - wxBitmap* bitmapSyncCfgSmallGrey; - wxBitmap* bitmapCmpCfg; - wxBitmap* bitmapPreview; - wxBitmap* bitmapPreviewDisabled; - wxBitmap* bitmapQuestion; - wxBitmap* bitmapCzechRep; - wxBitmap* bitmapChina; - wxBitmap* bitmapHolland; - wxBitmap* bitmapEngland; - wxBitmap* bitmapFrance; - wxBitmap* bitmapFinland; - wxBitmap* bitmapGermany; - wxBitmap* bitmapHungary; - wxBitmap* bitmapRomania; - wxBitmap* bitmapTaiwan; - wxBitmap* bitmapTurkey; - wxBitmap* bitmapItaly; - wxBitmap* bitmapJapan; - wxBitmap* bitmapPoland; - wxBitmap* bitmapPortugal; - wxBitmap* bitmapBrazil; - wxBitmap* bitmapSlovakia; - wxBitmap* bitmapSpain; - wxBitmap* bitmapRussia; - wxBitmap* bitmapSyncCreateLeftAct; - wxBitmap* bitmapSyncCreateLeftDeact; - wxBitmap* bitmapSyncCreateRightAct; - wxBitmap* bitmapSyncCreateRightDeact; - wxBitmap* bitmapSyncDeleteLeftAct; - wxBitmap* bitmapSyncDeleteLeftDeact; - wxBitmap* bitmapSyncDeleteRightAct; - wxBitmap* bitmapSyncDeleteRightDeact; - wxBitmap* bitmapSyncDirLeftAct; - wxBitmap* bitmapSyncDirLeftDeact; - wxBitmap* bitmapSyncDirRightAct; - wxBitmap* bitmapSyncDirRightDeact; - wxBitmap* bitmapSyncDirNoneAct; - wxBitmap* bitmapSyncDirNoneDeact; - wxBitmap* bitmapSyncDirLeftSmall; - wxBitmap* bitmapSyncDirRightSmall; - wxBitmap* bitmapSyncDirNoneSmall; - wxBitmap* bitmapCreateLeftSmall; - wxBitmap* bitmapCreateRightSmall; - wxBitmap* bitmapDeleteLeftSmall; - wxBitmap* bitmapDeleteRightSmall; - wxBitmap* bitmapLeftOnlySmall; - wxBitmap* bitmapRightOnlySmall; - wxBitmap* bitmapLeftNewerSmall; - wxBitmap* bitmapRightNewerSmall; - wxBitmap* bitmapEqualSmall; - wxBitmap* bitmapDifferentSmall; - wxBitmap* bitmapConflictSmall; - wxBitmap* bitmapCreate; - wxBitmap* bitmapUpdate; - wxBitmap* bitmapDelete; - wxBitmap* bitmapData; - wxBitmap* bitmapCmpViewSmall; - wxBitmap* bitmapSyncViewSmall; - wxBitmap* bitmapSwitchViewSmall; - + //global image resource objects wxAnimation* animationMoney; wxAnimation* animationSync; - wxIcon* programIcon; void load() const; //loads bitmap resources on program startup: logical const! diff --git a/library/statistics.cpp b/library/statistics.cpp index 53a75fce..f4319686 100644 --- a/library/statistics.cpp +++ b/library/statistics.cpp @@ -113,10 +113,10 @@ Statistics::Statistics(const int totalObjectCount, remainingTimeLast(256*256*256*100), //something "big" timer(new wxStopWatch) {} - Statistics::~Statistics() - { - delete timer; - } +Statistics::~Statistics() +{ + delete timer; +} void Statistics::addMeasurement(const int objectsCurrent, const double dataCurrent) { diff --git a/library/statistics.h b/library/statistics.h index d1b8b98b..a8aa140f 100644 --- a/library/statistics.h +++ b/library/statistics.h @@ -39,7 +39,7 @@ public: const unsigned windowSizeRemainingTime, //time in ms const unsigned windowSizeBytesPerSecond); //time in ms - ~Statistics(); + ~Statistics(); void addMeasurement(const int objectsCurrent, const double dataCurrent); wxString getRemainingTime() const; //returns the remaining time in milliseconds diff --git a/shared/buildInfo.h b/shared/buildInfo.h new file mode 100644 index 00000000..1c14caa5 --- /dev/null +++ b/shared/buildInfo.h @@ -0,0 +1,12 @@ +#ifndef BUILDINFO_H_INCLUDED +#define BUILDINFO_H_INCLUDED + +namespace Utility +{ +//determine build info +//seems to be safer than checking for _WIN64 (defined on windows for 64-bit compilations only) while _WIN32 is always defined +static const bool is32BitBuild = sizeof(void*) == 4; +static const bool is64BitBuild = sizeof(void*) == 8; +} + +#endif // BUILDINFO_H_INCLUDED diff --git a/shared/customButton.cpp b/shared/customButton.cpp index 40c0397f..73b9d1ee 100644 --- a/shared/customButton.cpp +++ b/shared/customButton.cpp @@ -277,17 +277,17 @@ void wxButtonWithImage::refreshButtonLabel() //wxDC::DrawLabel() unfortunately isn't working for transparent images on Linux, so we need to use custom image-concatenation if (bitmapFront.IsOk()) - writeToImage(wxImage(bitmapFront.ConvertToImage()), + writeToImage(bitmapFront.ConvertToImage(), wxPoint(0, (transparentImage.GetHeight() - bitmapFront.GetHeight()) / 2), transparentImage); if (bitmapText.IsOk()) - writeToImage(wxImage(bitmapText.ConvertToImage()), + writeToImage(bitmapText.ConvertToImage(), wxPoint(bitmapFront.GetWidth() + m_spaceAfter, (transparentImage.GetHeight() - bitmapText.GetHeight()) / 2), transparentImage); if (bitmapBack.IsOk()) - writeToImage(wxImage(bitmapBack.ConvertToImage()), + writeToImage(bitmapBack.ConvertToImage(), wxPoint(bitmapFront.GetWidth() + m_spaceAfter + bitmapText.GetWidth() + m_spaceBefore, (transparentImage.GetHeight() - bitmapBack.GetHeight()) / 2), transparentImage); diff --git a/shared/customComboBox.cpp b/shared/customComboBox.cpp index f2eec7a9..e21e915c 100644 --- a/shared/customComboBox.cpp +++ b/shared/customComboBox.cpp @@ -50,6 +50,10 @@ void CustomComboBox::OnKeyEvent(wxKeyEvent& event) void CustomComboBox::addPairToFolderHistory(const wxString& newFolder, unsigned int maxHistSize) { + //don't add empty directories + if (newFolder.empty()) + return; + const wxString oldVal = this->GetValue(); //insert new folder or put it to the front if already existing diff --git a/shared/dllLoader.cpp b/shared/dllLoader.cpp index e37ded54..fbfa5b11 100644 --- a/shared/dllLoader.cpp +++ b/shared/dllLoader.cpp @@ -1,44 +1,55 @@ #include "dllLoader.h" #include <wx/msw/wrapwin.h> //includes "windows.h" +#include <map> +#include <assert.h> namespace { -class KernelDllHandler //dynamically load "kernel32.dll" +class DllHandler //dynamically load "kernel32.dll" { public: - static const KernelDllHandler& getInstance() + static DllHandler& getInstance() { - static KernelDllHandler instance; + static DllHandler instance; return instance; } - HINSTANCE getHandle() const + HINSTANCE getHandle(const std::wstring& libraryName) { - return hKernel; + HandleMap::const_iterator foundEntry = handles.find(libraryName); + if (foundEntry == handles.end()) + { + HINSTANCE newHandle = ::LoadLibrary(libraryName.c_str()); + handles.insert(std::make_pair(libraryName, newHandle)); + + assert(handles.find(libraryName) != handles.end()); + return newHandle; + } + else + return foundEntry->second; } private: - KernelDllHandler() : - hKernel(NULL) - { - //get a handle to the DLL module containing required functionality - hKernel = ::LoadLibrary(L"kernel32.dll"); - } + DllHandler() {} - ~KernelDllHandler() + ~DllHandler() { - if (hKernel) ::FreeLibrary(hKernel); + for (HandleMap::const_iterator i = handles.begin(); i != handles.end(); ++i) + if (i->second != NULL) ::FreeLibrary(i->second); } - HINSTANCE hKernel; + typedef std::map<std::wstring, HINSTANCE> HandleMap; + HandleMap handles; }; } -void* Utility::loadSymbolKernel(const std::string& functionName) +void* Utility::loadSymbol(const std::wstring& libraryName, const std::string& functionName) { - if (KernelDllHandler::getInstance().getHandle() != NULL) - return reinterpret_cast<void*>(::GetProcAddress(KernelDllHandler::getInstance().getHandle(), functionName.c_str())); + const HINSTANCE libHandle = DllHandler::getInstance().getHandle(libraryName); + + if (libHandle != NULL) + return reinterpret_cast<void*>(::GetProcAddress(libHandle, functionName.c_str())); else return NULL; } diff --git a/shared/dllLoader.h b/shared/dllLoader.h index bf62b542..5b561c5a 100644 --- a/shared/dllLoader.h +++ b/shared/dllLoader.h @@ -5,10 +5,11 @@ namespace Utility { - //load kernel dll functions -template <typename FunctionType> -FunctionType loadDllFunKernel(const std::string& functionName); +//load function from a DLL library, e.g. from kernel32.dll +//NOTE: you're allowed to take a static reference to the return value to optimize performance! :) +template <typename FunctionType> +FunctionType loadDllFunction(const std::wstring& libraryName, const std::string& functionName); @@ -22,13 +23,13 @@ FunctionType loadDllFunKernel(const std::string& functionName); //---------------Inline Implementation--------------------------------------------------- -void* loadSymbolKernel(const std::string& functionName); +void* loadSymbol(const std::wstring& libraryName, const std::string& functionName); template <typename FunctionType> inline -FunctionType loadDllFunKernel(const std::string& functionName) +FunctionType loadDllFunction(const std::wstring& libraryName, const std::string& functionName) { - return reinterpret_cast<FunctionType>(loadSymbolKernel(functionName)); + return reinterpret_cast<FunctionType>(loadSymbol(libraryName, functionName)); } #ifndef FFS_WIN diff --git a/shared/fileHandling.cpp b/shared/fileHandling.cpp index 4b9901e0..ef1d3e6c 100644 --- a/shared/fileHandling.cpp +++ b/shared/fileHandling.cpp @@ -14,9 +14,11 @@ #include <wx/utils.h> #ifdef FFS_WIN +#include "recycler.h" #include "dllLoader.h" #include <wx/msw/wrapwin.h> //includes "windows.h" #include "shadow.h" +#include "longPathPrefix.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -104,83 +106,48 @@ Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) if (dirnameTmp.empty()) //an empty string is interpreted as "\"; this is not desired return Zstring(); - if (!dirnameTmp.EndsWith(zToWx(globalFunctions::FILE_NAME_SEPARATOR))) - dirnameTmp += zToWx(globalFunctions::FILE_NAME_SEPARATOR); - //replace macros expandMacros(dirnameTmp); +#ifdef FFS_WIN + /* + resolve relative names; required by: + - \\?\-prefix which needs absolute names + - Volume Shadow Copy: volume name needs to be part of each filename + - file icon buffer (at least for extensions that are acutally read from disk, e.g. "exe") + - detection of dependent directories, e.g. "\" and "C:\test" + */ + dirnameTmp = resolveRelativePath(dirnameTmp.c_str()).c_str(); +#endif + + if (!dirnameTmp.EndsWith(zToWx(globalFunctions::FILE_NAME_SEPARATOR))) + dirnameTmp += zToWx(globalFunctions::FILE_NAME_SEPARATOR); + return wxToZ(dirnameTmp); } -class RecycleBin +bool FreeFileSync::recycleBinExists() { -public: - static const RecycleBin& getInstance() - { - static RecycleBin instance; //lazy creation of RecycleBin - return instance; - } - - bool recycleBinExists() const - { - return recycleBinAvailable; - } - - bool moveToRecycleBin(const Zstring& filename) const; //throw (std::logic_error) - -private: - RecycleBin() : - recycleBinAvailable(false) - { #ifdef FFS_WIN - recycleBinAvailable = true; + return true; +#else + return false; #endif // FFS_WIN - } - - ~RecycleBin() {} - -private: - bool recycleBinAvailable; -}; +} -bool RecycleBin::moveToRecycleBin(const Zstring& filename) const //throw (std::logic_error) +inline +void moveToRecycleBin(const Zstring& filename) //throw (std::logic_error), throw (FileError) { - if (!recycleBinAvailable) //this method should ONLY be called if recycle bin is available + if (!FreeFileSync::recycleBinExists()) //this method should ONLY be called if recycle bin is available throw std::logic_error("Initialization of Recycle Bin failed!"); #ifdef FFS_WIN - Zstring filenameDoubleNull = filename + wxChar(0); - - SHFILEOPSTRUCT fileOp; - fileOp.hwnd = NULL; - fileOp.wFunc = FO_DELETE; - fileOp.pFrom = filenameDoubleNull.c_str(); - fileOp.pTo = NULL; - fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; - fileOp.fAnyOperationsAborted = false; - fileOp.hNameMappings = NULL; - fileOp.lpszProgressTitle = NULL; - - if (SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) return false; + FreeFileSync::moveToWindowsRecycler(filename); //throw (FileError) +#else + throw std::logic_error("No Recycler for Linux available at the moment!"); #endif - - return true; -} - - -bool FreeFileSync::recycleBinExists() -{ - return RecycleBin::getInstance().recycleBinExists(); -} - - -inline -bool moveToRecycleBin(const Zstring& filename) //throw (std::logic_error) -{ - return RecycleBin::getInstance().moveToRecycleBin(filename); } @@ -190,7 +157,7 @@ bool FreeFileSync::fileExists(const DefaultChar* filename) #ifdef FFS_WIN // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them - const DWORD ret = ::GetFileAttributes(filename); + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(filename).c_str()); return (ret != INVALID_FILE_ATTRIBUTES) && !(ret & FILE_ATTRIBUTE_DIRECTORY); //returns true for (file-)symlinks also @@ -208,7 +175,7 @@ bool FreeFileSync::dirExists(const DefaultChar* dirname) #ifdef FFS_WIN // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them - const DWORD ret = ::GetFileAttributes(dirname); + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(dirname).c_str()); return (ret != INVALID_FILE_ATTRIBUTES) && (ret & FILE_ATTRIBUTE_DIRECTORY); //returns true for (dir-)symlinks also @@ -223,7 +190,7 @@ bool FreeFileSync::dirExists(const DefaultChar* dirname) bool FreeFileSync::symlinkExists(const DefaultChar* objname) { #ifdef FFS_WIN - const DWORD ret = ::GetFileAttributes(objname); + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(objname).c_str()); return (ret != INVALID_FILE_ATTRIBUTES) && (ret & FILE_ATTRIBUTE_REPARSE_POINT); #elif defined FFS_LINUX @@ -263,8 +230,8 @@ bool FreeFileSync::isMovable(const Zstring& pathFrom, const Zstring& pathTo) const bool result = //try to move the file #ifdef FFS_WIN - ::MoveFileEx(dummyFileSource.c_str(), //__in LPCTSTR lpExistingFileName, - dummyFileTarget.c_str(), //__in_opt LPCTSTR lpNewFileName, + ::MoveFileEx(applyLongPathPrefix(dummyFileSource).c_str(), //__in LPCTSTR lpExistingFileName, + applyLongPathPrefix(dummyFileTarget).c_str(), //__in_opt LPCTSTR lpNewFileName, 0) != 0; //__in DWORD dwFlags #elif defined FFS_LINUX ::rename(dummyFileSource.c_str(), dummyFileTarget.c_str()) == 0; @@ -285,7 +252,9 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) { //no error situation if file is not existing! manual deletion relies on it! #ifdef FFS_WIN - if (::GetFileAttributes(filename.c_str()) == INVALID_FILE_ATTRIBUTES) + + const Zstring filenameFmt = applyLongPathPrefix(filename); + if (::GetFileAttributes(filenameFmt.c_str()) == INVALID_FILE_ATTRIBUTES) return; //neither file nor any other object with that name existing #elif defined FFS_LINUX @@ -296,15 +265,14 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) if (useRecycleBin) { - if (!moveToRecycleBin(filename)) - throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(filename) + wxT("\"")); + ::moveToRecycleBin(filename); return; } #ifdef FFS_WIN //initialize file attributes if (!::SetFileAttributes( - filename.c_str(), //address of filename + filenameFmt.c_str(), //address of filename FILE_ATTRIBUTE_NORMAL)) //attributes to set { wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\""); @@ -312,7 +280,7 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) } //remove file, support for \\?\-prefix - if (!::DeleteFile(filename.c_str())) + if (!::DeleteFile(filenameFmt.c_str())) { wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); @@ -331,9 +299,9 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) void FreeFileSync::renameFile(const Zstring& oldName, const Zstring& newName) //throw (FileError); { #ifdef FFS_WIN - if (!::MoveFileEx(oldName.c_str(), //__in LPCTSTR lpExistingFileName, - newName.c_str(), //__in_opt LPCTSTR lpNewFileName, - 0)) //__in DWORD dwFlags + if (!::MoveFileEx(applyLongPathPrefix(oldName).c_str(), //__in LPCTSTR lpExistingFileName, + applyLongPathPrefix(newName).c_str(), //__in_opt LPCTSTR lpNewFileName, + 0)) //__in DWORD dwFlags { const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(oldName) + wxT("\" ->\n\"") + zToWx(newName) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); @@ -388,8 +356,8 @@ void FreeFileSync::moveFile(const Zstring& sourceFile, const Zstring& targetFile #ifdef FFS_WIN //first try to move the file directly without copying - if (::MoveFileEx(sourceFile.c_str(), //__in LPCTSTR lpExistingFileName, - targetFile.c_str(), //__in_opt LPCTSTR lpNewFileName, + if (::MoveFileEx(applyLongPathPrefix(sourceFile).c_str(), //__in LPCTSTR lpExistingFileName, + applyLongPathPrefix(targetFile).c_str(), //__in_opt LPCTSTR lpNewFileName, 0)) //__in DWORD dwFlags return; @@ -494,8 +462,8 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool { //first try to move the directory directly without copying #ifdef FFS_WIN - if (::MoveFileEx(sourceDir.c_str(), //__in LPCTSTR lpExistingFileName, - targetDir.c_str(), //__in_opt LPCTSTR lpNewFileName, + if (::MoveFileEx(applyLongPathPrefix(sourceDir).c_str(), //__in LPCTSTR lpExistingFileName, + applyLongPathPrefix(targetDir).c_str(), //__in_opt LPCTSTR lpNewFileName, 0)) //__in DWORD dwFlags return; @@ -615,7 +583,9 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc { //no error situation if directory is not existing! manual deletion relies on it! #ifdef FFS_WIN - const DWORD dirAttr = GetFileAttributes(directory.c_str()); //name of a file or directory + const Zstring directoryFmt = applyLongPathPrefix(directory); //support for \\?\-prefix + + const DWORD dirAttr = ::GetFileAttributes(directoryFmt.c_str()); //name of a file or directory if (dirAttr == INVALID_FILE_ATTRIBUTES) return; //neither directory nor any other object with that name existing @@ -627,8 +597,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc if (useRecycleBin) { - if (!moveToRecycleBin(directory)) - throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(directory) + wxT("\"")); + ::moveToRecycleBin(directory); return; } @@ -636,7 +605,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc #ifdef FFS_WIN //initialize file attributes if (!::SetFileAttributes( // initialize file attributes: actually NEEDED for symbolic links also! - directory.c_str(), // address of directory name + directoryFmt.c_str(), // address of directory name FILE_ATTRIBUTE_NORMAL)) // attributes to set { wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); @@ -645,9 +614,9 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc //attention: check if directory is a symlink! Do NOT traverse into it deleting contained files!!! - if (dirAttr & FILE_ATTRIBUTE_REPARSE_POINT) //remove symlink directly, support for \\?\-prefix + if (dirAttr & FILE_ATTRIBUTE_REPARSE_POINT) //remove symlink directly { - if (!::RemoveDirectory(directory.c_str())) + if (!::RemoveDirectory(directoryFmt.c_str())) { wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); @@ -683,7 +652,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc //parent directory is deleted last #ifdef FFS_WIN //remove directory, support for \\?\-prefix - if (!::RemoveDirectory(directory.c_str())) + if (!::RemoveDirectory(directoryFmt.c_str())) #else if (::rmdir(directory.c_str()) != 0) #endif @@ -718,7 +687,7 @@ void FreeFileSync::copyFileTimes(const Zstring& sourceDir, const Zstring& target return; #ifdef FFS_WIN - HANDLE hDirRead = ::CreateFile(sourceDir.c_str(), + HANDLE hDirRead = ::CreateFile(applyLongPathPrefix(sourceDir).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -737,7 +706,7 @@ void FreeFileSync::copyFileTimes(const Zstring& sourceDir, const Zstring& target &accessTime, &lastWriteTime)) { - HANDLE hDirWrite = ::CreateFile(targetDir.c_str(), + HANDLE hDirWrite = ::CreateFile(applyLongPathPrefix(targetDir).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -776,13 +745,13 @@ void FreeFileSync::copyFileTimes(const Zstring& sourceDir, const Zstring& target Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory { //open handle to target of symbolic link - HANDLE hDir = ::CreateFile(dirLinkName.c_str(), - 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); + const HANDLE hDir = ::CreateFile(FreeFileSync::applyLongPathPrefix(dirLinkName).c_str(), + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); if (hDir == INVALID_HANDLE_VALUE) return Zstring(); @@ -799,7 +768,7 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa DWORD cchFilePath, DWORD dwFlags); static const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = - Utility::loadDllFunKernel<GetFinalPathNameByHandleWFunc>("GetFinalPathNameByHandleW"); + Utility::loadDllFunction<GetFinalPathNameByHandleWFunc>(L"kernel32.dll", "GetFinalPathNameByHandleW"); if (getFinalPathNameByHandle == NULL) throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); @@ -885,10 +854,10 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat //now creation should be possible #ifdef FFS_WIN - const DWORD templateAttr = ::GetFileAttributes(templateDir.c_str()); //replaces wxDirExists(): also returns successful for broken symlinks + const DWORD templateAttr = ::GetFileAttributes(applyLongPathPrefix(templateDir).c_str()); //replaces wxDirExists(): also returns successful for broken symlinks if (templateAttr == INVALID_FILE_ATTRIBUTES) //fallback { - if (!::CreateDirectory(directory.c_str(), // pointer to a directory path string + if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string NULL) && level == 0) { const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); @@ -910,8 +879,8 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat else { if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered - linkPath.c_str(), // pointer to path string of template directory - directory.c_str(), // pointer to a directory path string + applyLongPathPrefix(linkPath).c_str(), // pointer to path string of template directory + applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string NULL) && level == 0) { const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); @@ -924,12 +893,16 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat } else //in all other cases { - if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered - templateDir.c_str(), // pointer to path string of template directory - directory.c_str(), // pointer to a directory path string + if (!::CreateDirectoryEx( // this function automatically copies symbolic links if encountered + applyLongPathPrefix(templateDir).c_str(), // pointer to path string of template directory + applyLongPathPrefixCreateDir(directory).c_str(), // pointer to a directory path string NULL) && level == 0) { - const wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + const wxString errorMessage = templateAttr & FILE_ATTRIBUTE_REPARSE_POINT ? + //give a more meaningful errormessage if copying a symbolic link failed, e.g. "C:\Users\ZenJu\Application Data" + (wxString(_("Error copying symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\" ->\n\"") + directory.c_str() + wxT("\"")) : + + (wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"")); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } @@ -960,7 +933,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat if (symlink(buffer, directory.c_str()) != 0) { - wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""); + const wxString errorMessage = wxString(_("Error copying symbolic link:")) + wxT("\n\"") + zToWx(templateDir) + wxT("\" ->\n\"") + zToWx(directory) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } return; //symlink created successfully @@ -1022,7 +995,7 @@ Zstring createTempName(const Zstring& filename) { //if it's not unique, add a postfix number int postfix = 1; - while (FreeFileSync::fileExists(output + DefaultChar('_') + numberToZstring(postfix))) + while (FreeFileSync::fileExists(output + DefaultStr("_") + numberToZstring(postfix))) ++postfix; output += Zstring(DefaultStr("_")) + numberToZstring(postfix); @@ -1107,9 +1080,10 @@ bool supportForNonEncryptedDestination() ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - //symbolic links are supported starting with Vista + //encrypted destination is not supported with Windows 2000 if (GetVersionEx(&osvi)) - return osvi.dwMajorVersion >= 5 && osvi.dwMinorVersion >= 1; //XP has majorVersion == 5, minorVersion == 1, Vista majorVersion == 6 + return osvi.dwMajorVersion > 5 || + (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 0); //2000 has majorVersion == 5, minorVersion == 0 //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx return false; } @@ -1121,6 +1095,10 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, FreeFileSync::ShadowCopy* shadowCopyHandler, FreeFileSync::CopyFileCallback* callback) { + //FreeFileSync::fileExists(targetFile.c_str()) -> avoid this call, performance; + //if target exists (very unlikely, because sync-algorithm deletes it) renaming below will fail! + + DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS; //copy symbolic links instead of the files pointed at @@ -1133,11 +1111,11 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, if (nonEncSupported) copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; - const Zstring temporary = createTempName(targetFile); //use temporary file until a correct date has been set + if (!::CopyFileEx( //same performance as CopyFile() - sourceFile.c_str(), - temporary.c_str(), + applyLongPathPrefix(sourceFile).c_str(), + applyLongPathPrefix(temporary).c_str(), copyCallbackInternal, callback, NULL, @@ -1152,6 +1130,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, (lastError == ERROR_SHARING_VIOLATION || lastError == ERROR_LOCK_VIOLATION)) { + //shadowFilename already contains prefix: E.g. "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Program Files\FFS\sample.dat" const Zstring shadowFilename(shadowCopyHandler->makeShadowCopy(sourceFile)); copyFile(shadowFilename, //transferred bytes is automatically reset when new file is copied targetFile, @@ -1161,12 +1140,33 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, return; } - const wxString errorMessage = wxString(_("Error copying file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)); + //assemble error message... + const wxString errorMessage = wxString(_("Error copying file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\"") + + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError); + + throw FileError(errorMessage); } - //rename temporary file - FreeFileSync::renameFile(temporary, targetFile); + try + { + //rename temporary file + FreeFileSync::renameFile(temporary, targetFile); + } + catch (...) //if renaming temporary failed: cleanup + { + try + { + removeFile(temporary, false); //throw (FileError, std::logic_error); + } + catch(...) {} + + //this can only happen in very obscure situations: while scanning, target didn't exist, but while sync'ing it suddenly does (e.g. network drop?) + if (FreeFileSync::fileExists(targetFile.c_str())) + throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\"\n\n") + + _("Target file already existing!")); + + throw; + } //copy creation date (last modification date is redundantly written, too) copyFileTimes(sourceFile, targetFile); //throw() @@ -1230,7 +1230,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, if (symlink(buffer, targetFile.c_str()) != 0) { - const wxString errorMessage = wxString(_("Error writing file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\""); + const wxString errorMessage = wxString(_("Error copying symbolic link:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } @@ -1254,12 +1254,12 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, //create targetFile and open it for writing const Zstring temporary = createTempName(targetFile); //use temporary file until a correct date has been set - std::ofstream fileOut(temporary.c_str(), std::ios_base::binary); - if (fileOut.fail()) - throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\"")); - try { + std::ofstream fileOut(temporary.c_str(), std::ios_base::binary); + if (fileOut.fail()) + throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\"")); + //copy contents of sourceFile to targetFile wxULongLong totalBytesTransferred; static MemoryAllocator memory; @@ -1326,8 +1326,11 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, catch (...) { //try to delete target file if error occured, or exception was thrown in callback function + //no data-loss, because of "fileExists(targetFile))" check at the beginning! if (FreeFileSync::fileExists(targetFile)) ::unlink(targetFile); //don't handle error situations! + + //clean-up temporary if (FreeFileSync::fileExists(temporary)) ::unlink(temporary); //don't handle error situations! diff --git a/shared/fileHandling.h b/shared/fileHandling.h index b12f6f03..95d8fddd 100644 --- a/shared/fileHandling.h +++ b/shared/fileHandling.h @@ -1,5 +1,5 @@ -#ifndef RECYCLER_H_INCLUDED -#define RECYCLER_H_INCLUDED +#ifndef RECYCLER2_H_INCLUDED +#define RECYCLER2_H_INCLUDED #include "zstring.h" #include "fileError.h" @@ -83,4 +83,4 @@ void copyFile(const Zstring& sourceFile, } -#endif // RECYCLER_H_INCLUDED +#endif // RECYCLER2_H_INCLUDED diff --git a/shared/fileID.cpp b/shared/fileID.cpp new file mode 100644 index 00000000..005707dc --- /dev/null +++ b/shared/fileID.cpp @@ -0,0 +1,82 @@ +#include "fileID.h" + +#ifdef FFS_WIN +#include "staticAssert.h" +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "longPathPrefix.h" + +#elif defined FFS_LINUX + +#endif + + + +#ifdef FFS_WIN +class CloseHandleOnExit +{ +public: + CloseHandleOnExit(HANDLE fileHandle) : fileHandle_(fileHandle) {} + + ~CloseHandleOnExit() + { + ::CloseHandle(fileHandle_); + } + +private: + HANDLE fileHandle_; +}; + + +Utility::FileID Utility::retrieveFileID(const Zstring& filename) +{ + //ensure our DWORD_FFS really is the same as DWORD + assert_static(sizeof(Utility::FileID::DWORD_FFS) == sizeof(DWORD)); + +//WARNING: CreateFile() is SLOW, while GetFileInformationByHandle() is quite cheap! +//http://msdn.microsoft.com/en-us/library/aa363788(VS.85).aspx + + const HANDLE hFile = ::CreateFile(FreeFileSync::applyLongPathPrefix(filename).c_str(), + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, //FILE_FLAG_BACKUP_SEMANTICS needed to open directories + NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandleOnExit dummy(hFile); + + BY_HANDLE_FILE_INFORMATION info; + if (::GetFileInformationByHandle(hFile, &info)) + { + return Utility::FileID(info.dwVolumeSerialNumber, + info.nFileIndexHigh, + info.nFileIndexLow); + } + } + return Utility::FileID(); //empty ID +} + + +#elif defined FFS_LINUX +Utility::FileID Utility::retrieveFileID(const Zstring& filename) +{ + struct stat fileInfo; + if (::lstat(filename.c_str(), &fileInfo) == 0) //lstat() does not resolve symlinks + return Utility::FileID(fileInfo.st_dev, fileInfo.st_ino); + + return Utility::FileID(); //empty ID +} +#endif + + +bool Utility::sameFileSpecified(const Zstring& file1, const Zstring& file2) +{ + const Utility::FileID id1 = retrieveFileID(file1); + const Utility::FileID id2 = retrieveFileID(file2); + + if (id1 != FileID() && id2 != FileID()) + return id1 == id2; + + return false; +} diff --git a/shared/fileID.h b/shared/fileID.h new file mode 100644 index 00000000..7944b368 --- /dev/null +++ b/shared/fileID.h @@ -0,0 +1,194 @@ +#ifndef FILEID_H_INCLUDED +#define FILEID_H_INCLUDED + +#include <wx/stream.h> +#include "zstring.h" + +#ifdef FFS_WIN +#elif defined FFS_LINUX +#include <sys/stat.h> +#endif + + +//unique file identifier +namespace Utility +{ +class FileID +{ +public: + //standard copy constructor and assignment operator are okay! + + FileID(wxInputStream& stream); //read + void toStream(wxOutputStream& stream) const; //write + + bool isNull() const; + bool operator==(const FileID& rhs) const; + bool operator!=(const FileID& rhs) const; + bool operator<(const FileID& rhs) const; + + FileID(); +#ifdef FFS_WIN + typedef unsigned long DWORD_FFS; //we don't want do include "windows.h" or "<wx/msw/wrapwin.h>" here, do we? + + FileID(DWORD_FFS dwVolumeSN, + DWORD_FFS fileIndexHi, + DWORD_FFS fileIndexLo); +#elif defined FFS_LINUX + FileID(dev_t devId, + ino_t inId); +#endif +private: +#ifdef FFS_WIN + DWORD_FFS dwVolumeSerialNumber; + DWORD_FFS nFileIndexHigh; + DWORD_FFS nFileIndexLow; +#elif defined FFS_LINUX + dev_t deviceId; + ino_t inodeId; +#endif +}; + +//get unique file id (symbolic link handling: opens the link!!!) +//error condition: returns FileID () +FileID retrieveFileID(const Zstring& filename); + +//test whether two distinct paths point to the same file or directory: +// true: paths point to same files/dirs +// false: error occured OR point to different files/dirs +bool sameFileSpecified(const Zstring& file1, const Zstring& file2); +} + + + + + + + + + + + + + + + + + + + +//---------------Inline Implementation--------------------------------------------------- +#ifdef FFS_WIN +inline +Utility::FileID::FileID() : + dwVolumeSerialNumber(0), + nFileIndexHigh(0), + nFileIndexLow(0) {} + +inline +Utility::FileID::FileID(DWORD_FFS dwVolumeSN, + DWORD_FFS fileIndexHi, + DWORD_FFS fileIndexLo) : + dwVolumeSerialNumber(dwVolumeSN), + nFileIndexHigh(fileIndexHi), + nFileIndexLow(fileIndexLo) {} + +inline +bool Utility::FileID::isNull() const +{ + return dwVolumeSerialNumber == 0 && + nFileIndexHigh == 0 && + nFileIndexLow == 0; +} + +inline +bool Utility::FileID::operator==(const FileID& rhs) const +{ + return dwVolumeSerialNumber == rhs.dwVolumeSerialNumber && + nFileIndexHigh == rhs.nFileIndexHigh && + nFileIndexLow == rhs.nFileIndexLow; +} + +inline +bool Utility::FileID::operator<(const FileID& rhs) const +{ + if (dwVolumeSerialNumber != rhs.dwVolumeSerialNumber) + return dwVolumeSerialNumber < rhs.dwVolumeSerialNumber; + + if (nFileIndexHigh != rhs.nFileIndexHigh) + return nFileIndexHigh < rhs.nFileIndexHigh; + + return nFileIndexLow < rhs.nFileIndexLow; +} + +inline +Utility::FileID::FileID(wxInputStream& stream) //read +{ + stream.Read(&dwVolumeSerialNumber, sizeof(dwVolumeSerialNumber)); + stream.Read(&nFileIndexHigh, sizeof(nFileIndexHigh)); + stream.Read(&nFileIndexLow, sizeof(nFileIndexLow)); +} + +inline +void Utility::FileID::toStream(wxOutputStream& stream) const //write +{ + stream.Write(&dwVolumeSerialNumber, sizeof(dwVolumeSerialNumber)); + stream.Write(&nFileIndexHigh, sizeof(nFileIndexHigh)); + stream.Write(&nFileIndexLow, sizeof(nFileIndexLow)); +} + +#elif defined FFS_LINUX +inline +Utility::FileID::FileID() : + deviceId(0), + inodeId(0) {} + +inline +Utility::FileID::FileID(dev_t devId, + ino_t inId) : + deviceId(devId), + inodeId(inId) {} + +inline +bool Utility::FileID::isNull() const +{ + return deviceId == 0 && + inodeId == 0; +} + +inline +bool Utility::FileID::operator==(const FileID& rhs) const +{ + return deviceId == rhs.deviceId && + inodeId == rhs.inodeId; +} + +inline +bool Utility::FileID::operator<(const FileID& rhs) const +{ + if (deviceId != rhs.deviceId) + return deviceId < rhs.deviceId; + + return inodeId < rhs.inodeId; +} + +inline +Utility::FileID::FileID(wxInputStream& stream) //read +{ + stream.Read(&deviceId, sizeof(deviceId)); + stream.Read(&inodeId, sizeof(inodeId)); +} + +inline +void Utility::FileID::toStream(wxOutputStream& stream) const //write +{ + stream.Write(&deviceId, sizeof(deviceId)); + stream.Write(&inodeId, sizeof(inodeId)); +} +#endif +inline +bool Utility::FileID::operator!=(const FileID& rhs) const +{ + return !(*this == rhs); +} + +#endif // FILEID_H_INCLUDED diff --git a/shared/fileTraverser.cpp b/shared/fileTraverser.cpp index c323f1a3..7d2615bf 100644 --- a/shared/fileTraverser.cpp +++ b/shared/fileTraverser.cpp @@ -6,6 +6,7 @@ #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" +#include "longPathPrefix.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -22,7 +23,7 @@ public: ~CloseHandleOnExit() { - CloseHandle(fileHandle_); + ::CloseHandle(fileHandle_); } private: @@ -65,7 +66,7 @@ inline bool setWin32FileInformationFromSymlink(const Zstring linkName, FreeFileSync::TraverseCallback::FileInfo& output) { //open handle to target of symbolic link - HANDLE hFile = ::CreateFile(linkName.c_str(), + HANDLE hFile = ::CreateFile(FreeFileSync::applyLongPathPrefix(linkName).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, @@ -129,8 +130,8 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* directory + globalFunctions::FILE_NAME_SEPARATOR; WIN32_FIND_DATA fileMetaData; - HANDLE searchHandle = FindFirstFile((directoryFormatted + DefaultChar('*')).c_str(), //__in LPCTSTR lpFileName - &fileMetaData); //__out LPWIN32_FIND_DATA lpFindFileData + HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryFormatted + DefaultChar('*')).c_str(), //__in LPCTSTR lpFileName + &fileMetaData); //__out LPWIN32_FIND_DATA lpFindFileData //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH if (searchHandle == INVALID_HANDLE_VALUE) @@ -140,8 +141,10 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* return true; //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; - switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError))) + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted(lastError); + + switch (sink->onError(errorMessage)) { case TraverseCallback::TRAVERSING_STOP: return false; @@ -205,8 +208,8 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* } } } - while (FindNextFile(searchHandle, // handle to search - &fileMetaData)); // pointer to structure for data on found file + while (::FindNextFile(searchHandle, // handle to search + &fileMetaData)); // pointer to structure for data on found file const DWORD lastError = ::GetLastError(); if (lastError == ERROR_NO_MORE_FILES) @@ -362,3 +365,6 @@ void FreeFileSync::traverseFolder(const Zstring& directory, else traverseDirectory<false>(directoryFormatted, sink, 0); } + + + diff --git a/shared/localization.cpp b/shared/localization.cpp index ad3cbb99..5f017989 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -53,7 +53,7 @@ LocalizationInfo::LocalizationInfo() newEntry.languageID = wxLANGUAGE_SPANISH; newEntry.languageName = wxT("Español"); newEntry.languageFile = wxT("spanish.lng"); - newEntry.translatorName = wxT("David RodrÃguez"); + newEntry.translatorName = wxT("Alexis MartÃnez"); newEntry.languageFlag = wxT("spain.png"); locMapping.push_back(newEntry); @@ -134,6 +134,13 @@ LocalizationInfo::LocalizationInfo() newEntry.languageFlag = wxT("finland.png"); locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_SWEDISH; + newEntry.languageName = wxT("Svenska"); + newEntry.languageFile = wxT("swedish.lng"); + newEntry.translatorName = wxT("Ã…ke Engelbrektson"); + newEntry.languageFlag = wxT("sweden.png"); + locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_TURKISH; newEntry.languageName = wxT("Türkçe"); newEntry.languageFile = wxT("turkish.lng"); @@ -230,6 +237,10 @@ int mapLanguageDialect(const int language) case wxLANGUAGE_SPANISH_VENEZUELA: return wxLANGUAGE_SPANISH; + //variants of wxLANGUAGE_SWEDISH + case wxLANGUAGE_SWEDISH_FINLAND: + return wxLANGUAGE_SWEDISH; + //case wxLANGUAGE_CZECH: //case wxLANGUAGE_FINNISH: //case wxLANGUAGE_JAPANESE: diff --git a/shared/longPathPrefix.cpp b/shared/longPathPrefix.cpp new file mode 100644 index 00000000..9ce74c8b --- /dev/null +++ b/shared/longPathPrefix.cpp @@ -0,0 +1,95 @@ +#include "longPathPrefix.h" +#include <boost/scoped_array.hpp> +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "fileError.h" +#include "systemFunctions.h" +#include "stringConv.h" +#include <wx/intl.h> + +namespace +{ +Zstring getFullPathName(const Zstring& relativeName, size_t proposedBufferSize = 1000) +{ + using namespace FreeFileSync; + + boost::scoped_array<DefaultChar> fullPath(new DefaultChar[proposedBufferSize]); + const DWORD rv = ::GetFullPathName( + relativeName.c_str(), //__in LPCTSTR lpFileName, + proposedBufferSize, //__in DWORD nBufferLength, + fullPath.get(), //__out LPTSTR lpBuffer, + NULL); //__out LPTSTR *lpFilePart + if (rv == 0 || rv == proposedBufferSize) + throw FileError(wxString(_("Error resolving full path name:")) + wxT("\n\"") + zToWx(relativeName) + wxT("\"") + + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + if (rv > proposedBufferSize) + return getFullPathName(relativeName, rv); + + return fullPath.get(); +} +} + + +Zstring FreeFileSync::resolveRelativePath(const Zstring& path) //throw() +{ + try + { + return getFullPathName(path); + } + catch (...) + { + return path; + } +} + + +//there are two flavors of long path prefix: one for UNC paths, one for regular paths +const Zstring LONG_PATH_PREFIX = DefaultStr("\\\\?\\"); +const Zstring LONG_PATH_PREFIX_UNC = DefaultStr("\\\\?\\UNC"); + +template <size_t max_path> +inline +Zstring applyLongPathPrefixImpl(const Zstring& path) +{ + if ( path.length() >= max_path && //maximum allowed path length without prefix is (MAX_PATH - 1) + !path.StartsWith(LONG_PATH_PREFIX)) + { + if (path.StartsWith(DefaultStr("\\\\"))) //UNC-name, e.g. \\zenju-pc\Users + return LONG_PATH_PREFIX_UNC + path.AfterFirst(DefaultChar('\\')); //convert to \\?\UNC\zenju-pc\Users + else + return LONG_PATH_PREFIX + path; //prepend \\?\ prefix + } + + //fallback + return path; +} + + +Zstring FreeFileSync::applyLongPathPrefix(const Zstring& path) +{ + return applyLongPathPrefixImpl<MAX_PATH>(path); +} + + +Zstring FreeFileSync::applyLongPathPrefixCreateDir(const Zstring& path) //throw() +{ + //special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold + return applyLongPathPrefixImpl<MAX_PATH - 12>(path); +} + + +Zstring FreeFileSync::removeLongPathPrefix(const Zstring& path) //throw() +{ + if (path.StartsWith(LONG_PATH_PREFIX)) + { + Zstring finalPath = path; + if (path.StartsWith(LONG_PATH_PREFIX_UNC)) //UNC-name + finalPath.Replace(LONG_PATH_PREFIX_UNC, DefaultStr("\\"), false); + else + finalPath.Replace(LONG_PATH_PREFIX, DefaultStr(""), false); + return finalPath; + } + + //fallback + return path; +} + diff --git a/shared/longPathPrefix.h b/shared/longPathPrefix.h new file mode 100644 index 00000000..e4834184 --- /dev/null +++ b/shared/longPathPrefix.h @@ -0,0 +1,27 @@ +#ifndef LONGPATHPREFIX_H_INCLUDED +#define LONGPATHPREFIX_H_INCLUDED + +#ifndef FFS_WIN +use in windows build only! +#endif + +#include "zstring.h" + +namespace FreeFileSync +{ + +Zstring resolveRelativePath(const Zstring& path); //throw() + +//handle filenames longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix (Reference: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath) +/* +1. path must be absolute +2. if path is smaller than MAX_PATH nothing is changed! +3. path may already contain \\?\-prefix +*/ +Zstring applyLongPathPrefix(const Zstring& path); //throw() +Zstring applyLongPathPrefixCreateDir(const Zstring& path); //throw() -> special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold + +Zstring removeLongPathPrefix(const Zstring& path); //throw() +} + +#endif // LONGPATHPREFIX_H_INCLUDED diff --git a/shared/recycler.cpp b/shared/recycler.cpp new file mode 100644 index 00000000..b3bb87dd --- /dev/null +++ b/shared/recycler.cpp @@ -0,0 +1,128 @@ +#include "recycler.h" +#include "dllLoader.h" +#include <wx/intl.h> +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "buildInfo.h" +#include "staticAssert.h" +#include <algorithm> +#include <functional> +//#include "../shared/longPathPrefix.h" + +const std::wstring& getRecyclerDllName() +{ + static const std::wstring filename( + Utility::is64BitBuild ? + L"Recycler_x64.dll": + L"Recycler_Win32.dll"); + + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + + return filename; +} + + +bool vistaOrLater() +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //IFileOperation is supported with Vista and later + if (GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5; + //XP has majorVersion == 5, minorVersion == 1 + //Vista has majorVersion == 6, minorVersion == 0 + //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} + +/* +Performance test: delete 1000 files +------------------------------------ +SHFileOperation - single file 33s +SHFileOperation - multiple files 2,1s +IFileOperation - single file 33s +IFileOperation - multiple files 2,1s + +=> SHFileOperation and IFileOperation have nearly IDENTICAL performance characteristics! + +Nevertheless, let's use IFileOperation for better error reporting! +*/ + +void FreeFileSync::moveToWindowsRecycler(const Zstring& fileToDelete) //throw (FileError) +{ + std::vector<Zstring> fileNames; + fileNames.push_back(fileToDelete); + moveToWindowsRecycler(fileNames); //throw (FileError) +} + + +void FreeFileSync::moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw (FileError) +{ + if (filesToDelete.empty()) + return; + + static const bool useIFileOperation = vistaOrLater(); + + if (useIFileOperation) //new recycle bin usage: available since Vista + { + typedef bool (*MoveToRecycleBinFunc)( + const wchar_t* fileNames[], + size_t fileNo, //size of fileNames array + wchar_t* errorMessage, + size_t errorBufferLen); + + static const MoveToRecycleBinFunc moveToRecycler = + Utility::loadDllFunction<MoveToRecycleBinFunc>(getRecyclerDllName().c_str(), "moveToRecycleBin"); + + if (moveToRecycler == NULL) + throw FileError(wxString(_("Could not load a required DLL:")) + wxT(" \"") + getRecyclerDllName().c_str() + wxT("\"")); + + //#warning moving long file paths to recycler does not work! clarify! +// std::vector<Zstring> temp; +// std::transform(filesToDelete.begin(), filesToDelete.end(), +// std::back_inserter(temp), std::ptr_fun(FreeFileSync::removeLongPathPrefix)); //::IFileOperation() can't handle \\?\-prefix! + + std::vector<const wchar_t*> fileNames; + std::transform(filesToDelete.begin(), filesToDelete.end(), + std::back_inserter(fileNames), std::mem_fun_ref(&Zstring::c_str)); + + wchar_t errorMessage[2000]; + if (!(*moveToRecycler)(&fileNames[0], //array must not be empty + fileNames.size(), + errorMessage, + 2000)) + { + throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + fileNames[0] + wxT("\"") + //report first file only... better than nothing + + wxT("\n\n") + + wxT("(") + errorMessage + wxT(")")); + } + } + else //regular recycle bin usage: available since XP + { + Zstring filenameDoubleNull; + for (std::vector<Zstring>::const_iterator i = filesToDelete.begin(); i != filesToDelete.end(); ++i) + { + //#warning moving long file paths to recycler does not work! clarify! + //filenameDoubleNull += removeLongPathPrefix(*i); //::SHFileOperation() can't handle \\?\-prefix! + filenameDoubleNull += *i; //::SHFileOperation() can't handle \\?\-prefix! + filenameDoubleNull += DefaultChar(0); + } + + SHFILEOPSTRUCT fileOp; + fileOp.hwnd = NULL; + fileOp.wFunc = FO_DELETE; + fileOp.pFrom = filenameDoubleNull.c_str(); + fileOp.pTo = NULL; + fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; + fileOp.fAnyOperationsAborted = false; + fileOp.hNameMappings = NULL; + fileOp.lpszProgressTitle = NULL; + + if (SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) + { + throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + filenameDoubleNull.c_str() + wxT("\"")); //report first file only... better than nothing + } + } +} + diff --git a/shared/recycler.h b/shared/recycler.h new file mode 100644 index 00000000..14aff4c0 --- /dev/null +++ b/shared/recycler.h @@ -0,0 +1,21 @@ +#ifndef RECYCLER_H_INCLUDED +#define RECYCLER_H_INCLUDED + +#include "fileError.h" +#include "zstring.h" +#include <vector> + +#ifndef FFS_WIN +use in windows build only! +#endif + + +namespace FreeFileSync +{ +//single-file processing +void moveToWindowsRecycler(const Zstring& fileToDelete); //throw (FileError) +//multi-file processing: about a factor of 15 faster than single-file +void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete); //throw (FileError) -> on error reports about first file only! +} + +#endif // RECYCLER_H_INCLUDED diff --git a/shared/shadow.cpp b/shared/shadow.cpp index 29eec53b..7e3b34c0 100644 --- a/shared/shadow.cpp +++ b/shared/shadow.cpp @@ -2,6 +2,10 @@ #include <wx/msw/wrapwin.h> //includes "windows.h" #include <wx/intl.h> #include "systemConstants.h" +#include "dllLoader.h" +#include <stdexcept> +#include "staticAssert.h" +#include "buildInfo.h" using FreeFileSync::ShadowCopy; @@ -12,7 +16,6 @@ bool newerThanXP() ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - //symbolic links are supported starting with Vista if (GetVersionEx(&osvi)) return osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 1) ; @@ -42,93 +45,78 @@ bool runningWOW64() //test if process is running under WOW64 (reference http://m } -class ShadowCopy::ShadowlDllHandler //dynamically load windows API functions +const wxString& getShadowDllName() { - typedef bool (*CreateShadowCopyFct)( //volumeName must end with "\", while shadowVolName does not end with "\" - const wchar_t* volumeName, - wchar_t* shadowVolName, - unsigned int shadowBufferLen, - void** backupHandle, - wchar_t* errorMessage, - unsigned int errorBufferLen); + /* + distinguish a bunch of VSS builds: we use XP and Server 2003 implementations... + VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx + */ - typedef void (*ReleaseShadowCopyFct)(void* backupHandle); + static const wxString filename( + Utility::is64BitBuild ? + (newerThanXP() ? + wxT("Shadow_Server2003_x64.dll") : + wxT("Shadow_XP_x64.dll")) : -public: - static const wxString& getShadowDllName() - { - /* - distinguish a bunch of VSS builds: we use XP and Server 2003 implementations... - VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx - */ -#if defined _WIN64 //note: _WIN32 is defined for 64-bit compilations, too, while _WIN64 only for 64-bit - static const wxString filename(newerThanXP() ? - wxT("Shadow_Server2003_x64.dll") : - wxT("Shadow_XP_x64.dll")); -#elif defined(_WIN32) - static const wxString filename(newerThanXP() ? - wxT("Shadow_Server2003_win32.dll") : - wxT("Shadow_XP_win32.dll")); -#else - Are we at 128 bit already? -#endif - return filename; - } + (newerThanXP() ? + wxT("Shadow_Server2003_Win32.dll") : + wxT("Shadow_XP_Win32.dll"))); - ShadowlDllHandler() : - createShadowCopy(NULL), - releaseShadowCopy(NULL), - hShadow(NULL) - { - //get a handle to the DLL module containing the required functionality - hShadow = ::LoadLibrary(getShadowDllName().c_str()); - if (hShadow) - { - createShadowCopy = reinterpret_cast<CreateShadowCopyFct>(::GetProcAddress(hShadow, "createShadowCopy")); - releaseShadowCopy = reinterpret_cast<ReleaseShadowCopyFct>(::GetProcAddress(hShadow, "releaseShadowCopy")); - } - } + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); - ~ShadowlDllHandler() - { - if (hShadow) ::FreeLibrary(hShadow); - } - - CreateShadowCopyFct createShadowCopy; - ReleaseShadowCopyFct releaseShadowCopy; + return filename; +} -private: - HINSTANCE hShadow; -}; //############################################################################################################# ShadowCopy::ShadowCopy() : - backupHandle(NULL) -{ - shadowDll = new ShadowlDllHandler; -} + backupHandle(NULL) {} ShadowCopy::~ShadowCopy() { if (backupHandle != NULL) - shadowDll->releaseShadowCopy(backupHandle); + { + typedef void (*ReleaseShadowCopyFct)(void* backupHandle); + static const ReleaseShadowCopyFct releaseShadowCopy = + Utility::loadDllFunction<ReleaseShadowCopyFct>(getShadowDllName().c_str(), "releaseShadowCopy"); + + if (releaseShadowCopy == NULL) + throw std::logic_error("Could not load \"releaseShadowCopy\"!"); //shouldn't arrive here! - delete shadowDll; + releaseShadowCopy(backupHandle); + } } Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) { + typedef bool (*CreateShadowCopyFct)( //volumeName must end with "\", while shadowVolName does not end with "\" + const wchar_t* volumeName, + wchar_t* shadowVolName, + unsigned int shadowBufferLen, + void** backupHandle, + wchar_t* errorMessage, + unsigned int errorBufferLen); + static const CreateShadowCopyFct createShadowCopy = + Utility::loadDllFunction<CreateShadowCopyFct>(getShadowDllName().c_str(), "createShadowCopy"); + + + typedef void (*ReleaseShadowCopyFct)(void* backupHandle); + static const ReleaseShadowCopyFct releaseShadowCopy = + Utility::loadDllFunction<ReleaseShadowCopyFct>(getShadowDllName().c_str(), "releaseShadowCopy"); + + + //check if shadow copy dll was loaded correctly - if ( shadowDll->createShadowCopy == NULL || - shadowDll->releaseShadowCopy == NULL) + if ( createShadowCopy == NULL || + releaseShadowCopy == NULL) { wxString errorMsg = _("Error copying locked file %x!"); errorMsg.Replace(wxT("%x"), wxString(wxT("\"")) + inputFile.c_str() + wxT("\"")); throw FileError(errorMsg + wxT("\n\n") + _("Error starting Volume Shadow Copy Service!") + wxT("\n") + - _("Could not load a required DLL:") + wxT(" \"") + ShadowlDllHandler::getShadowDllName() + wxT("\"")); + _("Could not load a required DLL:") + wxT(" \"") + getShadowDllName() + wxT("\"")); } //VSS does not support running under WOW64 except for Windows XP and Windows Server 2003 @@ -146,7 +134,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) //--------------------------------------------------------------------------------------------------------- wchar_t volumeNameRaw[1000]; - if (!GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, + if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName, volumeNameRaw, //__out LPTSTR lpszVolumePathName, 1000)) //__in DWORD cchBufferLength { @@ -164,7 +152,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) //release old shadow copy if (backupHandle != NULL) { - shadowDll->releaseShadowCopy(backupHandle); + releaseShadowCopy(backupHandle); backupHandle = NULL; } realVolumeLast.clear(); //...if next call fails... @@ -175,7 +163,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) void* backupHandleTmp = NULL; wchar_t errorMessage[1000]; - if (!shadowDll->createShadowCopy( + if (!createShadowCopy( volumeNameFormatted.c_str(), shadowVolName, 1000, @@ -194,7 +182,8 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) backupHandle = backupHandleTmp; } - const size_t pos = inputFile.find(volumeNameFormatted); + //input file is always absolute! directory formatting takes care of this! Therefore volume name can always be found. + const size_t pos = inputFile.find(volumeNameFormatted); //inputFile needs NOT to begin with volumeNameFormatted: consider for example \\?\ prefix! if (pos == Zstring::npos) { wxString errorMsg = _("Error copying locked file %x!"); @@ -209,4 +198,3 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) return shadowVolumeLast + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); } - diff --git a/shared/shadow.h b/shared/shadow.h index 79e0e59c..78100f78 100644 --- a/shared/shadow.h +++ b/shared/shadow.h @@ -23,9 +23,6 @@ private: ShadowCopy(const ShadowCopy&); ShadowCopy& operator=(const ShadowCopy&); - class ShadowlDllHandler; - const ShadowlDllHandler* shadowDll; - Zstring realVolumeLast; //buffer last volume name Zstring shadowVolumeLast; //buffer last created shadow volume void* backupHandle; diff --git a/shared/zstring.cpp b/shared/zstring.cpp index cb288ea2..c3d5ba8e 100644 --- a/shared/zstring.cpp +++ b/shared/zstring.cpp @@ -4,6 +4,7 @@ #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" #include "dllLoader.h" +#include <boost/scoped_array.hpp> #endif //FFS_WIN #ifdef __WXDEBUG__ @@ -45,60 +46,122 @@ AllocationCount& AllocationCount::getInstance() } #endif - #ifdef FFS_WIN +bool hasInvariantLocale() +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //invariant locale has been introduced with XP + if (GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5 || + (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1); //XP has majorVersion == 5, minorVersion == 1 + //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} #ifndef LOCALE_INVARIANT #define LOCALE_INVARIANT 0x007f #endif +//warning: LOCALE_INVARIANT is NOT available with Windows 2000, so we have to make yet another distinction... +namespace +{ +const LCID invariantLocale = hasInvariantLocale() ? + LOCALE_INVARIANT : + MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); //see: http://msdn.microsoft.com/en-us/goglobal/bb688122.aspx +} + inline -int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount = -1, const int bCount = -1) +int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB) { - //try to call "CompareStringOrdinal" first for low-level string comparison: unfortunately available not before Windows Vista! + //try to call "CompareStringOrdinal" for low-level string comparison: unfortunately available not before Windows Vista! + //by a factor ~3 faster than old string comparison using "LCMapString" typedef int (WINAPI *CompareStringOrdinalFunc)( LPCWSTR lpString1, int cchCount1, LPCWSTR lpString2, int cchCount2, BOOL bIgnoreCase); - static const CompareStringOrdinalFunc ordinalCompare = Utility::loadDllFunKernel<CompareStringOrdinalFunc>("CompareStringOrdinal"); + static const CompareStringOrdinalFunc ordinalCompare = Utility::loadDllFunction<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); - - //we're lucky here! This additional test for "CompareStringOrdinal" has no noticeable performance impact!! - if (ordinalCompare != NULL) + if (ordinalCompare != NULL) //this additional test has no noticeable performance impact { const int rv = (*ordinalCompare)( a, //pointer to first string - aCount, //size, in bytes or characters, of first string + sizeA, //size, in bytes or characters, of first string b, //pointer to second string - bCount, //size, in bytes or characters, of second string + sizeB, //size, in bytes or characters, of second string true); //ignore case - if (rv == 0) throw std::runtime_error("Error comparing strings (ordinal)!"); else return rv - 2; //convert to C-style string compare result } - else //fallback to "CompareString". Attention: this function is NOT accurate: for example "weiß" == "weiss"!!! + else //fallback { - //DON'T use lstrcmpi() here! It uses word sort and is locale dependent! - //Use CompareString() with "SORT_STRINGSORT" instead!!! +//do NOT use "CompareString"; this function is NOT accurate (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!! +//the only reliable way to compare filenames (with XP) is to call "CharUpper" or "LCMapString": - const int rv = CompareString( - LOCALE_INVARIANT, //locale independent - NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options - a, //pointer to first string - aCount, //size, in bytes or characters, of first string - b, //pointer to second string - bCount); //size, in bytes or characters, of second string + const size_t minSize = std::min(sizeA, sizeB); - if (rv == 0) - throw std::runtime_error("Error comparing strings!"); - else - return rv - 2; //convert to C-style string compare result + if (minSize == 0) //LCMapString does not allow input sizes of 0! + return sizeA - sizeB; + + int rv = 0; //always initialize... + if (minSize <= 5000) //performance optimization: stack + { + wchar_t bufferA[5000]; + wchar_t bufferB[5000]; + + if (::LCMapString( //faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString() + invariantLocale, //__in LCID Locale, + LCMAP_UPPERCASE, //__in DWORD dwMapFlags, + a, //__in LPCTSTR lpSrcStr, + minSize, //__in int cchSrc, + bufferA, //__out LPTSTR lpDestStr, + 5000 //__in int cchDest + ) == 0) + throw std::runtime_error("Error comparing strings! (LCMapString)"); + + if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, b, minSize, bufferB, 5000) == 0) + throw std::runtime_error("Error comparing strings! (LCMapString)"); + + rv = ::wmemcmp(bufferA, bufferB, minSize); + } + else //use freestore + { + boost::scoped_array<wchar_t> bufferA(new wchar_t[minSize]); + boost::scoped_array<wchar_t> bufferB(new wchar_t[minSize]); + + if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, a, minSize, bufferA.get(), minSize) == 0) + throw std::runtime_error("Error comparing strings! (LCMapString: FS)"); + + if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, b, minSize, bufferB.get(), minSize) == 0) + throw std::runtime_error("Error comparing strings! (LCMapString: FS)"); + + rv = ::wmemcmp(bufferA.get(), bufferB.get(), minSize); + } + + return rv == 0 ? + sizeA - sizeB : + rv; } + +// const int rv = CompareString( +// invariantLocale, //locale independent +// NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options +// a, //pointer to first string +// aCount, //size, in bytes or characters, of first string +// b, //pointer to second string +// bCount); //size, in bytes or characters, of second string +// +// if (rv == 0) +// throw std::runtime_error("Error comparing strings!"); +// else +// return rv - 2; //convert to C-style string compare result } #endif @@ -106,13 +169,13 @@ int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount = - #ifdef FFS_WIN int Zstring::CmpNoCase(const DefaultChar* other) const { - return ::compareStringsWin32(c_str(), other); //way faster than wxString::CmpNoCase()!! + return ::compareFilenamesWin32(c_str(), other, length(), ::wcslen(other)); //way faster than wxString::CmpNoCase() } int Zstring::CmpNoCase(const Zstring& other) const { - return ::compareStringsWin32(c_str(), other.c_str(), length(), other.length()); //way faster than wxString::CmpNoCase()!! + return ::compareFilenamesWin32(c_str(), other.c_str(), length(), other.length()); //way faster than wxString::CmpNoCase() } #endif @@ -277,14 +340,17 @@ std::vector<Zstring> Zstring::Tokenize(const DefaultChar delimiter) const #ifdef FFS_WIN -Zstring& Zstring::MakeLower() +Zstring& Zstring::MakeUpper() { const size_t thisLen = length(); if (thisLen == 0) return *this; reserve(thisLen); //make unshared - ::CharLower(data()); //use Windows' lower case conversion + + //use Windows' upper case conversion: faster than ::CharUpper() + if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, data(), thisLen, data(), thisLen) == 0) + throw std::runtime_error("Error converting to upper case! (LCMapString)"); return *this; } @@ -484,3 +550,4 @@ void Zstring::reserve(size_t capacityNeeded) //make unshared and check capacity descr->capacity = newCapacity; } } + diff --git a/shared/zstring.h b/shared/zstring.h index d0be30bf..cb047e15 100644 --- a/shared/zstring.h +++ b/shared/zstring.h @@ -52,7 +52,7 @@ public: #ifdef FFS_WIN int CmpNoCase(const DefaultChar* other) const; int CmpNoCase(const Zstring& other) const; - Zstring& MakeLower(); + Zstring& MakeUpper(); #endif int Cmp(const DefaultChar* other) const; int Cmp(const Zstring& other) const; @@ -134,6 +134,28 @@ template <class T> Zstring numberToZstring(const T& number); //convert number to Zstring + + + + + + + + + + + + + + + + + + + + + + //####################################################################################### //begin of implementation diff --git a/structures.cpp b/structures.cpp index 8653f43a..4cf6b335 100644 --- a/structures.cpp +++ b/structures.cpp @@ -64,13 +64,13 @@ SyncConfiguration::Variant SyncConfiguration::getVariant() const conflict == SYNC_DIR_NONE) return UPDATE; //Update -> - else if (exLeftSideOnly == SYNC_DIR_RIGHT && - exRightSideOnly == SYNC_DIR_LEFT && - leftNewer == SYNC_DIR_RIGHT && - rightNewer == SYNC_DIR_LEFT && - different == SYNC_DIR_NONE && - conflict == SYNC_DIR_NONE) - return TWOWAY; //two way <-> +// else if (exLeftSideOnly == SYNC_DIR_RIGHT && -> variant "twoway" is not selectable via gui anymore +// exRightSideOnly == SYNC_DIR_LEFT && +// leftNewer == SYNC_DIR_RIGHT && +// rightNewer == SYNC_DIR_LEFT && +// different == SYNC_DIR_NONE && +// conflict == SYNC_DIR_NONE) +// return TWOWAY; //two way <-> else return CUSTOM; //other } @@ -127,8 +127,7 @@ wxString SyncConfiguration::getVariantName() const return _("Mirror ->>"); case SyncConfiguration::UPDATE: return _("Update ->"); - case SyncConfiguration::TWOWAY: - return _("Two way <->"); + case SyncConfiguration::TWOWAY: //variant "twoway" is not selectable via gui anymore case SyncConfiguration::CUSTOM: return _("Custom"); } @@ -230,6 +229,8 @@ wxString FreeFileSync::getDescription(SyncOperation op) return _("Copy from left to right overwriting"); case SO_DO_NOTHING: return _("Do nothing"); + case SO_EQUAL: + return _("Files that are equal on both sides"); case SO_UNRESOLVED_CONFLICT: return _("Conflicts/files that cannot be categorized"); }; @@ -257,6 +258,8 @@ wxString FreeFileSync::getSymbol(SyncOperation op) return wxT("->"); case SO_DO_NOTHING: return wxT("-"); + case SO_EQUAL: + return wxT("'=="); //added quotation mark to avoid error in Excel cell when exporting to *.cvs case SO_UNRESOLVED_CONFLICT: return wxT("\\/\\->"); }; @@ -264,5 +267,3 @@ wxString FreeFileSync::getSymbol(SyncOperation op) assert(false); return wxEmptyString; } - - diff --git a/structures.h b/structures.h index ba9c3ada..212f9557 100644 --- a/structures.h +++ b/structures.h @@ -277,7 +277,8 @@ enum SyncOperation SO_DELETE_RIGHT, SO_OVERWRITE_LEFT, SO_OVERWRITE_RIGHT, - SO_DO_NOTHING, + SO_DO_NOTHING, //= both sides differ, but nothing will be synced + SO_EQUAL, //= both sides are equal, so nothing will be synced SO_UNRESOLVED_CONFLICT }; diff --git a/synchronization.cpp b/synchronization.cpp index fac3d9a4..b00d35b7 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -13,9 +13,11 @@ #include "shared/globalFunctions.h" #include <boost/scoped_array.hpp> #include <memory> +//#include "library/detectRenaming.h" #ifdef FFS_WIN #include "shared/shadow.h" +#include "shared/longPathPrefix.h" #endif using namespace FreeFileSync; @@ -74,6 +76,10 @@ int SyncStatistics::getConflict() const return conflict; } +const SyncStatistics::ConflictTexts& SyncStatistics::getFirstConflicts() const //get first few sync conflicts +{ + return firstConflicts; +} wxULongLong SyncStatistics::getDataToProcess() const { @@ -100,9 +106,6 @@ void SyncStatistics::getNumbersRecursively(const HierarchyObject& hierObj) rowsTotal += hierObj.subDirs.size(); rowsTotal += hierObj.subFiles.size(); - - //recurse into sub-dirs - std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), boost::bind(&SyncStatistics::getNumbersRecursively, this, _1)); } @@ -140,10 +143,13 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj) break; case SO_DO_NOTHING: + case SO_EQUAL: break; case SO_UNRESOLVED_CONFLICT: ++conflict; + if (firstConflicts.size() < 3) //save the first 3 conflict texts + firstConflicts.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict())); break; } } @@ -177,8 +183,12 @@ void SyncStatistics::getDirNumbers(const DirMapping& dirObj) break; case SO_DO_NOTHING: + case SO_EQUAL: break; } + + //recurse into sub-dirs + getNumbersRecursively(dirObj); } @@ -256,6 +266,7 @@ private: break; case SO_DO_NOTHING: + case SO_EQUAL: case SO_UNRESOLVED_CONFLICT: break; } @@ -437,16 +448,16 @@ bool deletionImminent(const FileSystemObject& fsObj) class RemoveInvalid { public: - RemoveInvalid(HierarchyObject& hierObj) : - hierObj_(hierObj) {} + RemoveInvalid(BaseDirMapping& baseDir) : + baseDir_(baseDir) {} ~RemoveInvalid() { - FileSystemObject::removeEmptyNonRec(hierObj_); + FileSystemObject::removeEmpty(baseDir_); } private: - HierarchyObject& hierObj_; + BaseDirMapping& baseDir_; }; @@ -477,9 +488,6 @@ public: template <bool deleteOnly> //"true" if files deletion shall happen only void execute(HierarchyObject& hierObj) { - //enforce removal of invalid entries (where both sides are empty) - RemoveInvalid dummy(hierObj); //non-recursive - //synchronize files: for (HierarchyObject::SubFileMapping::iterator i = hierObj.subFiles.begin(); i != hierObj.subFiles.end(); ++i) { @@ -516,7 +524,8 @@ public: case SO_DELETE_LEFT: case SO_DELETE_RIGHT: case SO_DO_NOTHING: - ; + case SO_EQUAL: + break; } } } @@ -680,6 +689,8 @@ void SyncRecursively::synchronizeFile(FileMapping& fileObj) const break; case SO_OVERWRITE_RIGHT: + target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>(); + statusText = txtOverwritingFile; statusText.Replace(DefaultStr("%x"), fileObj.getShortName<LEFT_SIDE>(), false); statusText.Replace(DefaultStr("%y"), fileObj.getFullName<RIGHT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false); @@ -687,10 +698,14 @@ void SyncRecursively::synchronizeFile(FileMapping& fileObj) const statusUpdater_.requestUiRefresh(); //trigger display refresh removeFile<RIGHT_SIDE>(fileObj, false); - copyFileUpdating(fileObj.getFullName<LEFT_SIDE>(), fileObj.getFullName<RIGHT_SIDE>(), fileObj.getFileSize<LEFT_SIDE>()); + fileObj.removeObject<RIGHT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) + + copyFileUpdating(fileObj.getFullName<LEFT_SIDE>(), target, fileObj.getFileSize<LEFT_SIDE>()); break; case SO_OVERWRITE_LEFT: + target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); + statusText = txtOverwritingFile; statusText.Replace(DefaultStr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false); statusText.Replace(DefaultStr("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR), false); @@ -698,10 +713,13 @@ void SyncRecursively::synchronizeFile(FileMapping& fileObj) const statusUpdater_.requestUiRefresh(); //trigger display refresh removeFile<LEFT_SIDE>(fileObj, false); - copyFileUpdating(fileObj.getFullName<RIGHT_SIDE>(), fileObj.getFullName<LEFT_SIDE>(), fileObj.getFileSize<RIGHT_SIDE>()); + fileObj.removeObject<LEFT_SIDE>(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) + + copyFileUpdating(fileObj.getFullName<RIGHT_SIDE>(), target, fileObj.getFileSize<RIGHT_SIDE>()); break; case SO_DO_NOTHING: + case SO_EQUAL: case SO_UNRESOLVED_CONFLICT: return; //no update on processed data! } @@ -715,6 +733,72 @@ void SyncRecursively::synchronizeFile(FileMapping& fileObj) const } +//class DetectRenamedFiles +//{ +//public: +// static void execute(BaseDirMapping& baseMap, StatusHandler& statusUpdater) +// { +// DetectRenamedFiles(baseMap, statusUpdater); +// } +// +//private: +// DetectRenamedFiles(BaseDirMapping& baseMap, StatusHandler& statusUpdater); +// +// template <SelectedSide renameOnSide> +// void renameFile(FileMapping& fileObjCreate, FileMapping& fileObjDelete) const; +// +// const Zstring txtRenamingFile; +// StatusHandler& statusUpdater_; +//}; + + +//DetectRenamedFiles::DetectRenamedFiles(BaseDirMapping& baseMap, StatusHandler& statusUpdater) : +// txtRenamingFile(wxToZ(_("Renaming file %x to %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)), +// statusUpdater_(statusUpdater) +//{ +// typedef std::vector<std::pair<CreateOnLeft, DeleteOnLeft> > RenameList; +// RenameList renameOnLeft; +// RenameList renameOnRight; +// FreeFileSync::getRenameCandidates(baseMap, renameOnLeft, renameOnRight); //throw()! +// +// for (RenameList::const_iterator i = renameOnLeft.begin(); i != renameOnLeft.end(); ++i) +// tryReportingError(statusUpdater_, boost::bind(&DetectRenamedFiles::renameFile<LEFT_SIDE>, this, boost::ref(*i->first), boost::ref(*i->second))); +// +// for (RenameList::const_iterator i = renameOnRight.begin(); i != renameOnRight.end(); ++i) +// tryReportingError(statusUpdater_, boost::bind(&DetectRenamedFiles::renameFile<RIGHT_SIDE>, this, boost::ref(*i->first), boost::ref(*i->second))); +//} + + +//template <SelectedSide renameOnSide> +//void DetectRenamedFiles::renameFile(FileMapping& fileObjCreate, FileMapping& fileObjDelete) const +//{ +// const SelectedSide sourceSide = renameOnSide == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE; +// +// Zstring statusText = txtRenamingFile; +// statusText.Replace(DefaultStr("%x"), fileObjDelete.getFullName<renameOnSide>(), false); +// statusText.Replace(DefaultStr("%y"), fileObjCreate.getRelativeName<sourceSide>(), false); +// statusUpdater_.updateStatusText(statusText); +// statusUpdater_.requestUiRefresh(); //trigger display refresh +// +// FreeFileSync::renameFile(fileObjDelete.getFullName<renameOnSide>(), +// fileObjDelete.getBaseDirPf<renameOnSide>() + fileObjCreate.getRelativeName<sourceSide>()); //throw (FileError); +// +// //update FileMapping +// fileObjCreate.synchronizeSides(); +// fileObjDelete.synchronizeSides(); +// +//#ifndef _MSC_VER +//#warning set FileID! +//#warning Test: zweimaliger rename sollte dann klappen +// +//#warning allgemein: FileID nach jedem kopieren neu bestimmen? +//#endif +// //progress indicator update +// //indicator is updated only if file is sync'ed correctly (and if some sync was done)! +// statusUpdater_.updateProcessedData(2, globalFunctions::convertToSigned(fileObjCreate.getFileSize<sourceSide>())); +//} + + template <FreeFileSync::SelectedSide side> inline void SyncRecursively::removeFolder(const DirMapping& dirObj) const @@ -838,6 +922,7 @@ void SyncRecursively::synchronizeFolder(DirMapping& dirObj) const case SO_UNRESOLVED_CONFLICT: assert(false); case SO_DO_NOTHING: + case SO_EQUAL: return; //no update on processed data! } @@ -879,6 +964,16 @@ bool dataLossPossible(const Zstring& dirName, const SyncStatistics& folderPairSt !dirName.empty() && !FreeFileSync::dirExists(dirName); } +namespace +{ +void makeSameLength(wxString& first, wxString& second) +{ + const size_t maxPref = std::max(first.length(), second.length()); + first.Pad(maxPref - first.length(), wxT(' '), true); + second.Pad(maxPref - second.length(), wxT(' '), true); +} +} + void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCfg>& syncConfig, FolderComparison& folderCmp) { @@ -978,8 +1073,24 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf //check if unresolved conflicts exist if (statisticsTotal.getConflict() > 0) - statusUpdater.reportWarning(_("Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization."), - m_warnings.warningUnresolvedConflicts); + { + //show the first few conflicts in warning message also: + wxString warningMessage = wxString(_("Unresolved conflicts existing!")) + + wxT(" (") + globalFunctions::numberToWxString(statisticsTotal.getConflict()) + wxT(")\n\n"); + + const SyncStatistics::ConflictTexts& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts + for (SyncStatistics::ConflictTexts::const_iterator i = firstConflicts.begin(); i != firstConflicts.end(); ++i) + warningMessage += wxString(wxT("\"")) + zToWx(i->first) + wxT("\": \t") + i->second + wxT("\n"); + + if (statisticsTotal.getConflict() > static_cast<int>(firstConflicts.size())) + warningMessage += wxT("[...]\n"); + else + warningMessage += wxT("\n"); + + warningMessage += _("You can ignore conflicts and continue synchronization."); + + statusUpdater.reportWarning(warningMessage, m_warnings.warningUnresolvedConflicts); + } //-------------------end of basic checks------------------------------------------ @@ -996,6 +1107,17 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf { const FolderPairSyncCfg& folderPairCfg = syncConfig[j - folderCmp.begin()]; +//------------------------------------------------------------------------------------------ + //info about folder pair to be processed (useful for logfile) + wxString left = wxString(_("Left")) + wxT(": "); + wxString right = wxString(_("Right")) + wxT(": "); + makeSameLength(left, right); + const wxString statusTxt = wxString(_("Processing folder pair:")) + wxT(" \n") + + wxT("\t") + left + wxT("\"") + zToWx(j->getBaseDir<LEFT_SIDE>()) + wxT("\"")+ wxT(" \n") + + wxT("\t") + right + wxT("\"") + zToWx(j->getBaseDir<RIGHT_SIDE>()) + wxT("\""); + statusUpdater.updateStatusText(wxToZ(statusTxt)); +//------------------------------------------------------------------------------------------ + //generate name of alternate deletion directory (unique for session AND folder pair) const DeletionHandling currentDelHandling(folderPairCfg.handleDeletion, folderPairCfg.custDelFolder); @@ -1005,6 +1127,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf //------------------------------------------------------------------------------------------ //execute synchronization recursively + //enforce removal of invalid entries (where both sides are empty) + RemoveInvalid dummy(*j); + + //detect renamed files: currently in automatic mode only + // if (folderPairCfg.inAutomaticMode) + // DetectRenamedFiles::execute(*j, statusUpdater); + //loop through all files twice; reason: first delete, then copy SyncRecursively( *this, #ifdef FFS_WIN @@ -1019,7 +1148,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf //------------------------------------------------------------------------------------------ //update synchronization database (automatic sync only) - if (folderPairCfg.updateSyncDB) + if (folderPairCfg.inAutomaticMode) { UpdateDatabase syncDB(*j, statusUpdater); statusUpdater.updateStatusText(wxToZ(_("Generating database..."))); @@ -1133,7 +1262,7 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback* c static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]); #ifdef FFS_WIN - wxFile file1(source.c_str(), wxFile::read); //don't use buffered file input for verification! + wxFile file1(FreeFileSync::applyLongPathPrefix(source).c_str(), wxFile::read); //don't use buffered file input for verification! #elif defined FFS_LINUX wxFile file1(::open(source.c_str(), O_RDONLY)); //utilize UTF-8 filename #endif @@ -1141,7 +1270,7 @@ void verifyFiles(const Zstring& source, const Zstring& target, VerifyCallback* c throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(source) + wxT("\"")); #ifdef FFS_WIN - wxFile file2(target.c_str(), wxFile::read); //don't use buffered file input for verification! + wxFile file2(FreeFileSync::applyLongPathPrefix(target).c_str(), wxFile::read); //don't use buffered file input for verification! #elif defined FFS_LINUX wxFile file2(::open(target.c_str(), O_RDONLY)); //utilize UTF-8 filename #endif @@ -1216,3 +1345,8 @@ void SyncRecursively::verifyFileCopy(const Zstring& source, const Zstring& targe } + + + + + diff --git a/synchronization.h b/synchronization.h index 53b17091..9db4d112 100644 --- a/synchronization.h +++ b/synchronization.h @@ -20,6 +20,10 @@ public: int getOverwrite(bool inclLeft = true, bool inclRight = true) const; int getDelete( bool inclLeft = true, bool inclRight = true) const; int getConflict() const; + + typedef std::vector<std::pair<Zstring, wxString> > ConflictTexts; // Pair(filename/conflict text) + const ConflictTexts& getFirstConflicts() const; //get first few sync conflicts + wxULongLong getDataToProcess() const; int getRowCount() const; @@ -35,6 +39,7 @@ private: int overwriteLeft, overwriteRight; int deleteLeft, deleteRight; int conflict; + ConflictTexts firstConflicts; //save the first few conflict texts to display as a warning message wxULongLong dataToProcess; int rowsTotal; }; @@ -45,14 +50,14 @@ class SyncRecursively; struct FolderPairSyncCfg { - FolderPairSyncCfg(bool inAutomaticMode, + FolderPairSyncCfg(bool automaticMode, const DeletionPolicy handleDel, const Zstring& custDelDir) : - updateSyncDB(inAutomaticMode), + inAutomaticMode(automaticMode), handleDeletion(handleDel), custDelFolder(custDelDir) {} - bool updateSyncDB; //update database if in automatic mode + bool inAutomaticMode; //update database if in automatic mode DeletionPolicy handleDeletion; Zstring custDelFolder; }; diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp index 0d203453..4d255950 100644 --- a/ui/MainDialog.cpp +++ b/ui/MainDialog.cpp @@ -228,6 +228,16 @@ private: }; +struct DirNotFound +{ + bool operator()(const FolderPairEnh& fp) const + { + return !dirExists(FreeFileSync::getFormattedDirectoryName(fp.leftDirectory)) || + !dirExists(FreeFileSync::getFormattedDirectoryName(fp.rightDirectory)); + } +}; + + //################################################################################################################################## MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, @@ -256,42 +266,43 @@ MainDialog::MainDialog(wxFrame* frame, //initialize and load configuration readGlobalSettings(); + bool loadCfgSuccess = false; if (cfgFileName.empty()) - readConfigurationFromXml(lastConfigFileName(), true); + loadCfgSuccess = readConfigurationFromXml(lastConfigFileName(), true); else - readConfigurationFromXml(cfgFileName, true); + loadCfgSuccess = readConfigurationFromXml(cfgFileName, true); //set icons for this dialog - m_bpButton10->SetBitmapLabel(*GlobalResources::getInstance().bitmapExit); - m_buttonCompare->setBitmapFront(*GlobalResources::getInstance().bitmapCompare); - m_bpButtonSyncConfig->SetBitmapLabel(*GlobalResources::getInstance().bitmapSyncCfg); - m_bpButtonCmpConfig->SetBitmapLabel(*GlobalResources::getInstance().bitmapCmpCfg); - m_bpButtonSave->SetBitmapLabel(*GlobalResources::getInstance().bitmapSave); - m_bpButtonLoad->SetBitmapLabel(*GlobalResources::getInstance().bitmapLoad); - m_bpButtonAddPair->SetBitmapLabel(*GlobalResources::getInstance().bitmapAddFolderPair); - m_bitmap15->SetBitmap(*GlobalResources::getInstance().bitmapStatusEdge); - - m_bitmapCreate->SetBitmap(*GlobalResources::getInstance().bitmapCreate); - m_bitmapUpdate->SetBitmap(*GlobalResources::getInstance().bitmapUpdate); - m_bitmapDelete->SetBitmap(*GlobalResources::getInstance().bitmapDelete); - m_bitmapData->SetBitmap(*GlobalResources::getInstance().bitmapData); + m_bpButton10->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("exit"))); + m_buttonCompare->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("compare"))); + m_bpButtonSyncConfig->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("syncConfig"))); + m_bpButtonCmpConfig->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("cmpConfig"))); + m_bpButtonSave->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("save"))); + m_bpButtonLoad->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("load"))); + m_bpButtonAddPair->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); + m_bitmap15->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusEdge"))); + + m_bitmapCreate->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("create"))); + m_bitmapUpdate->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("update"))); + m_bitmapDelete->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("delete"))); + m_bitmapData->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("data"))); bSizer6->Layout(); //wxButtonWithImage size might have changed //menu icons: workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) MenuItemUpdater updateMenuFile(m_menuFile); - updateMenuFile.addForUpdate(m_menuItem10, *GlobalResources::getInstance().bitmapCompareSmall); - updateMenuFile.addForUpdate(m_menuItem11, *GlobalResources::getInstance().bitmapSyncSmall); - updateMenuFile.addForUpdate(m_menuItemNew, *GlobalResources::getInstance().bitmapNewSmall); - updateMenuFile.addForUpdate(m_menuItemSave, *GlobalResources::getInstance().bitmapSaveSmall); - updateMenuFile.addForUpdate(m_menuItemLoad, *GlobalResources::getInstance().bitmapLoadSmall); + updateMenuFile.addForUpdate(m_menuItem10, GlobalResources::getInstance().getImageByName(wxT("compareSmall"))); + updateMenuFile.addForUpdate(m_menuItem11, GlobalResources::getInstance().getImageByName(wxT("syncSmall"))); + updateMenuFile.addForUpdate(m_menuItemNew, GlobalResources::getInstance().getImageByName(wxT("newSmall"))); + updateMenuFile.addForUpdate(m_menuItemSave, GlobalResources::getInstance().getImageByName(wxT("saveSmall"))); + updateMenuFile.addForUpdate(m_menuItemLoad, GlobalResources::getInstance().getImageByName(wxT("loadSmall"))); MenuItemUpdater updateMenuAdv(m_menuAdvanced); - updateMenuAdv.addForUpdate(m_menuItemGlobSett, *GlobalResources::getInstance().bitmapSettingsSmall); - updateMenuAdv.addForUpdate(m_menuItem7, *GlobalResources::getInstance().bitmapBatchSmall); + updateMenuAdv.addForUpdate(m_menuItemGlobSett, GlobalResources::getInstance().getImageByName(wxT("settingsSmall"))); + updateMenuAdv.addForUpdate(m_menuItem7, GlobalResources::getInstance().getImageByName(wxT("batchSmall"))); MenuItemUpdater updateMenuHelp(m_menuHelp); - updateMenuHelp.addForUpdate(m_menuItemAbout, *GlobalResources::getInstance().bitmapAboutSmall); + updateMenuHelp.addForUpdate(m_menuItemAbout, GlobalResources::getInstance().getImageByName(wxT("aboutSmall"))); //create language selection menu @@ -353,6 +364,22 @@ MainDialog::MainDialog(wxFrame* frame, //asynchronous call to wxWindow::Layout(): fix superfluous frame on right and bottom when FFS is started in fullscreen mode Connect(wxEVT_IDLE, wxIdleEventHandler(MainDialog::OnLayoutWindowAsync), NULL, this); + +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- + //some convenience: if FFS is started with a *.ffs_gui file as commandline parameter AND all directories contained exist, comparison shall be started right off + if (!cfgFileName.empty() && loadCfgSuccess) + { + const FreeFileSync::MainConfiguration currMainCfg = getCurrentConfiguration().mainCfg; + const bool allFoldersExist = !DirNotFound()(currMainCfg.firstPair) && + std::find_if(currMainCfg.additionalPairs.begin(), currMainCfg.additionalPairs.end(), + DirNotFound()) == currMainCfg.additionalPairs.end(); + if (allFoldersExist) + { + wxCommandEvent dummy2(wxEVT_COMMAND_BUTTON_CLICKED); + m_buttonCompare->AddPendingEvent(dummy2); //simulate button click on "compare" + } + } +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- } @@ -735,20 +762,15 @@ void exstractNames(const FileSystemObject& fsObj, wxString& name, wxString& dir) { if (!fsObj.isEmpty<side>()) { - const FileMapping* fileObj = dynamic_cast<const FileMapping*>(&fsObj); - if (fileObj != NULL) + if (isDirectoryMapping(fsObj)) { name = zToWx(fsObj.getFullName<side>()); - dir = zToWx(fsObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR)); + dir = name; } else { - const DirMapping* dirObj = dynamic_cast<const DirMapping*>(&fsObj); - if (dirObj != NULL) - { - name = zToWx(fsObj.getFullName<side>()); - dir = name; - } + name = zToWx(fsObj.getFullName<side>()); + dir = zToWx(fsObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR)); } } else @@ -1190,9 +1212,10 @@ void MainDialog::OnContextRim(wxGridEvent& event) //re-create context menu contextMenu.reset(new wxMenu); - if (syncPreview.previewIsEnabled()) + if (syncPreview.previewIsEnabled() && + fsObj && fsObj->getSyncOperation() != SO_EQUAL) { - if (fsObj && (selectionLeft.size() + selectionRight.size() > 0)) + if (selectionLeft.size() + selectionRight.size() > 0) { //CONTEXT_SYNC_DIR_LEFT wxMenuItem* menuItemSyncDirLeft = new wxMenuItem(contextMenu.get(), CONTEXT_SYNC_DIR_LEFT, wxString(_("Change direction")) + wxT("\tALT + LEFT")); @@ -1220,13 +1243,13 @@ void MainDialog::OnContextRim(wxGridEvent& event) if (fsObj->isActive()) { wxMenuItem* menuItemExclTemp = new wxMenuItem(contextMenu.get(), CONTEXT_FILTER_TEMP, wxString(_("Exclude temporarily")) + wxT("\tSPACE")); - menuItemExclTemp->SetBitmap(*GlobalResources::getInstance().bitmapCheckBoxFalse); + menuItemExclTemp->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("checkboxFalse"))); contextMenu->Append(menuItemExclTemp); } else { wxMenuItem* menuItemInclTemp = new wxMenuItem(contextMenu.get(), CONTEXT_FILTER_TEMP, wxString(_("Include temporarily")) + wxT("\tSPACE")); - menuItemInclTemp->SetBitmap(*GlobalResources::getInstance().bitmapCheckBoxTrue); + menuItemInclTemp->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("checkboxTrue"))); contextMenu->Append(menuItemInclTemp); } } @@ -1244,16 +1267,14 @@ void MainDialog::OnContextRim(wxGridEvent& event) const FileSystemObject* currObj = gridDataView->getObject(*i); if (currObj && !currObj->isEmpty<LEFT_SIDE>()) exFilterCandidateObj.push_back( - FilterObject(currObj->getRelativeName<LEFT_SIDE>(), - dynamic_cast<const DirMapping*>(currObj) != NULL)); + FilterObject(currObj->getRelativeName<LEFT_SIDE>(), isDirectoryMapping(*currObj))); } for (std::set<unsigned int>::const_iterator i = selectionRight.begin(); i != selectionRight.end(); ++i) { const FileSystemObject* currObj = gridDataView->getObject(*i); if (currObj && !currObj->isEmpty<RIGHT_SIDE>()) exFilterCandidateObj.push_back( - FilterObject(currObj->getRelativeName<RIGHT_SIDE>(), - dynamic_cast<const DirMapping*>(currObj) != NULL)); + FilterObject(currObj->getRelativeName<RIGHT_SIDE>(), isDirectoryMapping(*currObj))); } //############################################################################################### @@ -1267,7 +1288,7 @@ void MainDialog::OnContextRim(wxGridEvent& event) //add context menu item wxMenuItem* menuItemExclExt = new wxMenuItem(contextMenu.get(), CONTEXT_EXCLUDE_EXT, wxString(_("Exclude via filter:")) + wxT(" ") + wxT("*.") + zToWx(extension)); - menuItemExclExt->SetBitmap(*GlobalResources::getInstance().bitmapFilterSmall); + menuItemExclExt->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmall"))); contextMenu->Append(menuItemExclExt); //connect event @@ -1289,7 +1310,7 @@ void MainDialog::OnContextRim(wxGridEvent& event) if (menuItemExclObj != NULL) { - menuItemExclObj->SetBitmap(*GlobalResources::getInstance().bitmapFilterSmall); + menuItemExclObj->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmall"))); contextMenu->Append(menuItemExclObj); //connect event @@ -1603,9 +1624,9 @@ void MainDialog::OnContextMiddleLabel(wxGridEvent& event) wxMenuItem* itemCmpResult = new wxMenuItem(contextMenu.get(), CONTEXT_COMPARISON_RESULT, _("Comparison Result")); if (syncPreview.previewIsEnabled()) - itemSyncPreview->SetBitmap(*GlobalResources::getInstance().bitmapSyncViewSmall); + itemSyncPreview->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("syncViewSmall"))); else - itemCmpResult->SetBitmap(*GlobalResources::getInstance().bitmapCmpViewSmall); + itemCmpResult->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("cmpViewSmall"))); contextMenu->Append(itemCmpResult); contextMenu->Append(itemSyncPreview); @@ -1667,44 +1688,19 @@ wxString getFormattedHistoryElement(const wxString& filename) } -wxString getFullFilename(const wxString& name) -{ - //resolve relative names to avoid problems after working directory is changed - wxFileName filename(name); - if (!filename.Normalize()) - return name; //fallback - - return filename.GetFullPath(); -} - - -//tests if the same filenames are specified, even if they are relative to the current working directory -inline -bool sameFileSpecified(const wxString& file1, const wxString& file2) -{ - const wxString file1Full = getFullFilename(file1); - const wxString file2Full = getFullFilename(file2); - -#ifdef FFS_WIN //don't respect case in windows build - return file1Full.CmpNoCase(file2Full) == 0; -#elif defined FFS_LINUX - return file1Full == file2Full; -#endif -} - - +//tests if the same filenames are specified, even if they are relative to the current working directory/include symlinks or \\?\ prefix class FindDuplicates { public: - FindDuplicates(const wxString& name) : m_name(name) {} + FindDuplicates(const Zstring& name) : m_name(name) {} bool operator()(const wxString& other) const { - return sameFileSpecified(m_name, other); + return Utility::sameFileSpecified(m_name, wxToZ(other)); } private: - const wxString& m_name; + const Zstring& m_name; }; @@ -1714,7 +1710,7 @@ void MainDialog::addFileToCfgHistory(const wxString& filename) if (!wxFileExists(filename)) return; - std::vector<wxString>::const_iterator i = find_if(cfgFileNames.begin(), cfgFileNames.end(), FindDuplicates(filename)); + std::vector<wxString>::const_iterator i = find_if(cfgFileNames.begin(), cfgFileNames.end(), FindDuplicates(wxToZ(filename))); if (i != cfgFileNames.end()) { //if entry is in the list, then jump to element @@ -1725,7 +1721,7 @@ void MainDialog::addFileToCfgHistory(const wxString& filename) cfgFileNames.insert(cfgFileNames.begin(), filename); //the default config file should receive another name on GUI - if (sameFileSpecified(lastConfigFileName(), filename)) + if (Utility::sameFileSpecified(wxToZ(lastConfigFileName()), wxToZ(filename))) m_choiceHistory->Insert(_("<Last session>"), 0); //insert at beginning of list else m_choiceHistory->Insert(getFormattedHistoryElement(filename), 0); //insert at beginning of list @@ -1763,7 +1759,11 @@ void MainDialog::OnSaveConfig(wxCommandEvent& event) bool MainDialog::trySaveConfig() //return true if saved successfully { - const wxString defaultFileName = currentConfigFileName.empty() ? wxT("SyncSettings.ffs_gui") : currentConfigFileName; + wxString defaultFileName = currentConfigFileName.empty() ? wxT("SyncSettings.ffs_gui") : currentConfigFileName; + //attention: currentConfigFileName may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config! + if (defaultFileName.EndsWith(wxT(".ffs_batch"))) + defaultFileName.Replace(wxT(".ffs_batch"), wxT(".ffs_gui"), false); + wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("FreeFileSync configuration")) + wxT(" (*.ffs_gui)|*.ffs_gui"), wxFD_SAVE); if (filePicker->ShowModal() == wxID_OK) @@ -1937,7 +1937,7 @@ void MainDialog::OnSetSyncDirection(FFSSyncDirectionEvent& event) if (fsObj) { setSyncDirectionRec(event.direction, *fsObj); //set new direction (recursively) - FreeFileSync::setActiveStatus(true, *fsObj); //works recursively for directories + FreeFileSync::setActiveStatus(true, *fsObj); //works recursively for directories } } @@ -2291,75 +2291,75 @@ void MainDialog::OnSyncDirNone(wxCommandEvent& event) void MainDialog::initViewFilterButtons() { //compare result buttons - m_bpButtonLeftOnly->init(*GlobalResources::getInstance().bitmapLeftOnlyAct, + m_bpButtonLeftOnly->init(GlobalResources::getInstance().getImageByName(wxT("leftOnlyAct")), _("Hide files that exist on left side only"), - *GlobalResources::getInstance().bitmapLeftOnlyDeact, + GlobalResources::getInstance().getImageByName(wxT("leftOnlyDeact")), _("Show files that exist on left side only")); - m_bpButtonRightOnly->init(*GlobalResources::getInstance().bitmapRightOnlyAct, + m_bpButtonRightOnly->init(GlobalResources::getInstance().getImageByName(wxT("rightOnlyAct")), _("Hide files that exist on right side only"), - *GlobalResources::getInstance().bitmapRightOnlyDeact, + GlobalResources::getInstance().getImageByName(wxT("rightOnlyDeact")), _("Show files that exist on right side only")); - m_bpButtonLeftNewer->init(*GlobalResources::getInstance().bitmapLeftNewerAct, + m_bpButtonLeftNewer->init(GlobalResources::getInstance().getImageByName(wxT("leftNewerAct")), _("Hide files that are newer on left"), - *GlobalResources::getInstance().bitmapLeftNewerDeact, + GlobalResources::getInstance().getImageByName(wxT("leftNewerDeact")), _("Show files that are newer on left")); - m_bpButtonRightNewer->init(*GlobalResources::getInstance().bitmapRightNewerAct, + m_bpButtonRightNewer->init(GlobalResources::getInstance().getImageByName(wxT("rightNewerAct")), _("Hide files that are newer on right"), - *GlobalResources::getInstance().bitmapRightNewerDeact, + GlobalResources::getInstance().getImageByName(wxT("rightNewerDeact")), _("Show files that are newer on right")); - m_bpButtonEqual->init(*GlobalResources::getInstance().bitmapEqualAct, + m_bpButtonEqual->init(GlobalResources::getInstance().getImageByName(wxT("equalAct")), _("Hide files that are equal"), - *GlobalResources::getInstance().bitmapEqualDeact, + GlobalResources::getInstance().getImageByName(wxT("equalDeact")), _("Show files that are equal")); - m_bpButtonDifferent->init(*GlobalResources::getInstance().bitmapDifferentAct, + m_bpButtonDifferent->init(GlobalResources::getInstance().getImageByName(wxT("differentAct")), _("Hide files that are different"), - *GlobalResources::getInstance().bitmapDifferentDeact, + GlobalResources::getInstance().getImageByName(wxT("differentDeact")), _("Show files that are different")); - m_bpButtonConflict->init(*GlobalResources::getInstance().bitmapConflictAct, + m_bpButtonConflict->init(GlobalResources::getInstance().getImageByName(wxT("conflictAct")), _("Hide conflicts"), - *GlobalResources::getInstance().bitmapConflictDeact, + GlobalResources::getInstance().getImageByName(wxT("conflictDeact")), _("Show conflicts")); //sync preview buttons - m_bpButtonSyncCreateLeft->init(*GlobalResources::getInstance().bitmapSyncCreateLeftAct, + m_bpButtonSyncCreateLeft->init(GlobalResources::getInstance().getImageByName(wxT("syncCreateLeftAct")), _("Hide files that will be created on the left side"), - *GlobalResources::getInstance().bitmapSyncCreateLeftDeact, + GlobalResources::getInstance().getImageByName(wxT("syncCreateLeftDeact")), _("Show files that will be created on the left side")); - m_bpButtonSyncCreateRight->init(*GlobalResources::getInstance().bitmapSyncCreateRightAct, + m_bpButtonSyncCreateRight->init(GlobalResources::getInstance().getImageByName(wxT("syncCreateRightAct")), _("Hide files that will be created on the right side"), - *GlobalResources::getInstance().bitmapSyncCreateRightDeact, + GlobalResources::getInstance().getImageByName(wxT("syncCreateRightDeact")), _("Show files that will be created on the right side")); - m_bpButtonSyncDeleteLeft->init(*GlobalResources::getInstance().bitmapSyncDeleteLeftAct, + m_bpButtonSyncDeleteLeft->init(GlobalResources::getInstance().getImageByName(wxT("syncDeleteLeftAct")), _("Hide files that will be deleted on the left side"), - *GlobalResources::getInstance().bitmapSyncDeleteLeftDeact, + GlobalResources::getInstance().getImageByName(wxT("syncDeleteLeftDeact")), _("Show files that will be deleted on the left side")); - m_bpButtonSyncDeleteRight->init(*GlobalResources::getInstance().bitmapSyncDeleteRightAct, + m_bpButtonSyncDeleteRight->init(GlobalResources::getInstance().getImageByName(wxT("syncDeleteRightAct")), _("Hide files that will be deleted on the right side"), - *GlobalResources::getInstance().bitmapSyncDeleteRightDeact, + GlobalResources::getInstance().getImageByName(wxT("syncDeleteRightDeact")), _("Show files that will be deleted on the right side")); - m_bpButtonSyncDirOverwLeft->init(*GlobalResources::getInstance().bitmapSyncDirLeftAct, + m_bpButtonSyncDirOverwLeft->init(GlobalResources::getInstance().getImageByName(wxT("syncDirLeftAct")), _("Hide files that will be overwritten on left side"), - *GlobalResources::getInstance().bitmapSyncDirLeftDeact, + GlobalResources::getInstance().getImageByName(wxT("syncDirLeftDeact")), _("Show files that will be overwritten on left side")); - m_bpButtonSyncDirOverwRight->init(*GlobalResources::getInstance().bitmapSyncDirRightAct, + m_bpButtonSyncDirOverwRight->init(GlobalResources::getInstance().getImageByName(wxT("syncDirRightAct")), _("Hide files that will be overwritten on right side"), - *GlobalResources::getInstance().bitmapSyncDirRightDeact, + GlobalResources::getInstance().getImageByName(wxT("syncDirRightDeact")), _("Show files that will be overwritten on right side")); - m_bpButtonSyncDirNone->init(*GlobalResources::getInstance().bitmapSyncDirNoneAct, + m_bpButtonSyncDirNone->init(GlobalResources::getInstance().getImageByName(wxT("syncDirNoneAct")), _("Hide files that won't be copied"), - *GlobalResources::getInstance().bitmapSyncDirNoneDeact, + GlobalResources::getInstance().getImageByName(wxT("syncDirNoneDeact")), _("Show files that won't be copied")); //compare result buttons @@ -2388,8 +2388,8 @@ void MainDialog::updateFilterButtons() if (m_notebookBottomLeft->GetImageList() == NULL) { wxImageList* panelIcons = new wxImageList(16, 16); - panelIcons->Add(wxBitmap(*GlobalResources::getInstance().bitmapFilterSmall)); - panelIcons->Add(wxBitmap(*GlobalResources::getInstance().bitmapFilterSmallGrey)); + panelIcons->Add(wxBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmall")))); + panelIcons->Add(wxBitmap(GlobalResources::getInstance().getImageByName(wxT("filterSmallGrey")))); m_notebookBottomLeft->AssignImageList(panelIcons); //pass ownership } @@ -2400,7 +2400,7 @@ void MainDialog::updateFilterButtons() const bool isNullFilter = NameFilter(currentCfg.mainCfg.includeFilter, currentCfg.mainCfg.excludeFilter).isNull(); if (isNullFilter) { - m_bpButtonFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterOff); + m_bpButtonFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterOff"))); m_bpButtonFilter->SetToolTip(_("No filter selected")); //additional filter icon @@ -2408,7 +2408,7 @@ void MainDialog::updateFilterButtons() } else { - m_bpButtonFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterOn); + m_bpButtonFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterOn"))); m_bpButtonFilter->SetToolTip(_("Filter has been selected")); //show filter icon @@ -2417,7 +2417,7 @@ void MainDialog::updateFilterButtons() } else { - m_bpButtonFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterOff); + m_bpButtonFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterOff"))); m_bpButtonFilter->SetToolTip(_("Filtering is deactivated")); //additional filter icon @@ -2457,6 +2457,7 @@ void MainDialog::OnCompare(wxCommandEvent &event) FreeFileSync::CompareProcess comparison(currentCfg.mainCfg.hidden.traverseDirectorySymlinks, currentCfg.mainCfg.hidden.fileTimeTolerance, globalSettings.ignoreOneHourDiff, + globalSettings.detectRenameThreshold, globalSettings.optDialogs, &statusHandler); @@ -2469,6 +2470,11 @@ void MainDialog::OnCompare(wxCommandEvent &event) newCompareData); gridDataView->setData(newCompareData); //newCompareData is invalidated after this call + + //play (optional) sound notification after sync has completed (GUI and batch mode) + const wxString soundFile = FreeFileSync::getInstallationDir() + wxT("Compare_Complete.wav"); + if (fileExists(wxToZ(soundFile))) + wxSound::Play(soundFile, wxSOUND_ASYNC); } catch (AbortThisProcess&) { @@ -2932,6 +2938,7 @@ void MainDialog::updateGridViewData() m_bpButtonSyncDirOverwLeft-> isActive(), m_bpButtonSyncDirOverwRight->isActive(), m_bpButtonSyncDirNone-> isActive(), + m_bpButtonEqual-> isActive(), m_bpButtonConflict-> isActive()); filesOnLeftView = result.filesOnLeftView; @@ -2950,6 +2957,7 @@ void MainDialog::updateGridViewData() 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() || @@ -2959,6 +2967,7 @@ void MainDialog::updateGridViewData() m_bpButtonSyncDirOverwLeft-> IsShown() || m_bpButtonSyncDirOverwRight->IsShown() || m_bpButtonSyncDirNone-> IsShown() || + m_bpButtonEqual-> IsShown() || m_bpButtonConflict-> IsShown()) { m_panel112->Show(); @@ -3269,14 +3278,14 @@ void MainDialog::updateGuiForFolderPair() m_bpButtonLocalFilter->Hide(); m_bpButtonAltSyncCfg->Hide(); - m_bpButtonSwapSides->SetBitmapLabel(*GlobalResources::getInstance().bitmapSwap); + m_bpButtonSwapSides->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("swap"))); } else { m_bpButtonLocalFilter->Show(); m_bpButtonAltSyncCfg->Show(); - m_bpButtonSwapSides->SetBitmapLabel(*GlobalResources::getInstance().bitmapSwapSlim); + m_bpButtonSwapSides->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("swapSlim"))); } m_panelTopMiddle->Layout(); @@ -3427,6 +3436,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) exportString += wxString(wxT("\"")) + getDescription(SO_OVERWRITE_LEFT) + wxT("\";") + getSymbol(SO_OVERWRITE_LEFT) + wxT('\n'); exportString += wxString(wxT("\"")) + getDescription(SO_OVERWRITE_RIGHT) + wxT("\";") + getSymbol(SO_OVERWRITE_RIGHT) + wxT('\n'); exportString += wxString(wxT("\"")) + getDescription(SO_DO_NOTHING) + wxT("\";") + getSymbol(SO_DO_NOTHING) + wxT('\n'); + exportString += wxString(wxT("\"")) + getDescription(SO_DO_NOTHING) + wxT("\";") + getSymbol(SO_EQUAL) + wxT('\n'); exportString += wxString(wxT("\"")) + getDescription(SO_UNRESOLVED_CONFLICT) + wxT("\";") + getSymbol(SO_UNRESOLVED_CONFLICT) + wxT('\n'); } else @@ -3644,13 +3654,13 @@ void MainDialog::SyncPreview::enableSynchronization(bool value) { synchronizationEnabled = true; mainDlg_->m_buttonStartSync->SetForegroundColour(*wxBLACK); - mainDlg_->m_buttonStartSync->setBitmapFront(*GlobalResources::getInstance().bitmapSync); + mainDlg_->m_buttonStartSync->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("sync"))); } else { synchronizationEnabled = false; mainDlg_->m_buttonStartSync->SetForegroundColour(wxColor(128, 128, 128)); //Some colors seem to have problems with 16Bit color depth, well this one hasn't! - mainDlg_->m_buttonStartSync->setBitmapFront(*GlobalResources::getInstance().bitmapSyncDisabled); + mainDlg_->m_buttonStartSync->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("syncDisabled"))); } } @@ -3663,3 +3673,4 @@ bool MainDialog::SyncPreview::synchronizationIsEnabled() const + diff --git a/ui/MainDialog.h b/ui/MainDialog.h index 61f1537f..ff9fee09 100644 --- a/ui/MainDialog.h +++ b/ui/MainDialog.h @@ -82,7 +82,7 @@ public: MainDialog(wxFrame* frame, const wxString& cfgFileName, xmlAccess::XmlGlobalSettings& settings, - wxHelpController& helpController); + wxHelpController& helpController); ~MainDialog(); @@ -116,7 +116,7 @@ private: void removeAddFolderPair(const unsigned int pos); void clearAddFolderPairs(); -void updateGuiForFolderPair(); //helper method: add usability by showing/hiding buttons related to folder pairs + void updateGuiForFolderPair(); //helper method: add usability by showing/hiding buttons related to folder pairs //main method for putting gridDataView on UI: updates data respecting current view settings void updateGuiGrid(); @@ -267,7 +267,7 @@ void updateGuiForFolderPair(); //helper method: add usability by showing/hiding xmlAccess::XmlGuiConfig currentCfg; //folder pairs: - std::auto_ptr<FirstFolderPairCfg> firstFolderPair; //always bound!!! + std::auto_ptr<FirstFolderPairCfg> firstFolderPair; //always bound!!! std::vector<FolderPairPanel*> additionalFolderPairs; //additional pairs to the first pair //gui settings diff --git a/ui/SmallDialogs.cpp b/ui/SmallDialogs.cpp index 74678244..cab26472 100644 --- a/ui/SmallDialogs.cpp +++ b/ui/SmallDialogs.cpp @@ -14,16 +14,18 @@ #include <wx/wupdlock.h> #include "../shared/globalFunctions.h" #include "trayIcon.h" +#include "../shared/staticAssert.h" +#include "../shared/buildInfo.h" using namespace FreeFileSync; AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) { - m_bitmap9->SetBitmap(*GlobalResources::getInstance().bitmapWebsite); - m_bitmap10->SetBitmap(*GlobalResources::getInstance().bitmapEmail); - m_bitmap11->SetBitmap(*GlobalResources::getInstance().bitmapLogo); - m_bitmap13->SetBitmap(*GlobalResources::getInstance().bitmapGPL); + m_bitmap9->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("website"))); + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("email"))); + m_bitmap11->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("logo"))); + m_bitmap13->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("gpl"))); //create language credits for (std::vector<LocInfoLine>::const_iterator i = LocalizationInfo::getMapping().begin(); i != LocalizationInfo::getMapping().end(); ++i) @@ -49,10 +51,19 @@ AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode)"); + build += wxT(" - Unicode"); #else - build += wxT(" - ANSI)"); + build += wxT(" - ANSI"); #endif //wxUSE_UNICODE + + //compile time info about 32/64-bit build + if (Utility::is64BitBuild) + build += wxT(" x64)"); + else + build += wxT(" x86)"); + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + + m_build->SetLabel(build); m_animationControl1->SetAnimation(*GlobalResources::getInstance().animationMoney); @@ -80,7 +91,7 @@ HelpDlg::HelpDlg(wxWindow* window) : HelpDlgGenerated(window) { m_notebook1->SetFocus(); - m_bitmap25->SetBitmap(*GlobalResources::getInstance().bitmapHelp); + m_bitmap25->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("help"))); //populate decision trees: "compare by date" wxTreeItemId treeRoot = m_treeCtrl1->AddRoot(_("DECISION TREE")); @@ -137,10 +148,10 @@ FilterDlg::FilterDlg(wxWindow* window, includeFilter(filterIncl), excludeFilter(filterExcl) { - m_bitmap8->SetBitmap(*GlobalResources::getInstance().bitmapInclude); - m_bitmap9->SetBitmap(*GlobalResources::getInstance().bitmapExclude); - m_bitmap26->SetBitmap(*GlobalResources::getInstance().bitmapFilterOn); - m_bpButtonHelp->SetBitmapLabel(*GlobalResources::getInstance().bitmapHelp); + m_bitmap8->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("include"))); + m_bitmap9->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("exclude"))); + m_bitmap26->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("filterOn"))); + m_bpButtonHelp->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("help"))); m_textCtrlInclude->SetValue(zToWx(includeFilter)); m_textCtrlExclude->SetValue(zToWx(excludeFilter)); @@ -243,12 +254,12 @@ void DeleteDialog::updateTexts() if (m_checkBoxUseRecycler->GetValue()) { m_staticTextHeader->SetLabel(_("Do you really want to move the following objects(s) to the Recycle Bin?")); - m_bitmap12->SetBitmap(*GlobalResources::getInstance().bitmapRecycler); + m_bitmap12->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("recycler"))); } else { m_staticTextHeader->SetLabel(_("Do you really want to delete the following objects(s)?")); - m_bitmap12->SetBitmap(*GlobalResources::getInstance().bitmapDeleteFile); + m_bitmap12->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("deleteFile"))); } const std::pair<wxString, int> delInfo = FreeFileSync::deleteFromGridAndHDPreview( @@ -292,7 +303,7 @@ void DeleteDialog::OnUseRecycler(wxCommandEvent& event) { if (!FreeFileSync::recycleBinExists()) { - wxMessageBox(_("It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :)"), _("Error") , wxOK | wxICON_ERROR); + wxMessageBox(_("Unable to initialize Recycle Bin!"), _("Error") , wxOK | wxICON_ERROR); m_checkBoxUseRecycler->SetValue(false); } } @@ -307,7 +318,7 @@ ErrorDlg::ErrorDlg(wxWindow* parentWindow, const int activeButtons, const wxStri ErrorDlgGenerated(parentWindow), ignoreErrors(ignoreNextErrors) { - m_bitmap10->SetBitmap(*GlobalResources::getInstance().bitmapError); + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("error"))); m_textCtrl8->SetValue(messageText); m_checkBoxIgnoreErrors->SetValue(ignoreNextErrors); @@ -368,7 +379,7 @@ WarningDlg::WarningDlg(wxWindow* parentWindow, int activeButtons, const wxStrin WarningDlgGenerated(parentWindow), dontShowAgain(dontShowDlgAgain) { - m_bitmap10->SetBitmap(*GlobalResources::getInstance().bitmapWarning); + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("warning"))); m_textCtrl8->SetValue(messageText); m_checkBoxDontShowAgain->SetValue(dontShowAgain); @@ -418,7 +429,7 @@ QuestionDlg::QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxStri QuestionDlgGenerated(parentWindow), dontShowAgain(dontShowDlgAgain) { - m_bitmap10->SetBitmap(*GlobalResources::getInstance().bitmapQuestion); + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("question"))); m_textCtrl8->SetValue(messageText); if (dontShowAgain) m_checkBoxDontAskAgain->SetValue(*dontShowAgain); @@ -485,8 +496,8 @@ CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes output(attr), m_showFileIcons(showFileIcons) { - m_bpButton29->SetBitmapLabel(*GlobalResources::getInstance().bitmapMoveUp); - m_bpButton30->SetBitmapLabel(*GlobalResources::getInstance().bitmapMoveDown); + m_bpButton29->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("moveUp"))); + m_bpButton30->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("moveDown"))); xmlAccess::ColumnAttributes columnSettings = attr; @@ -604,12 +615,11 @@ SyncPreviewDlg::SyncPreviewDlg(wxWindow* parentWindow, using FreeFileSync::includeNumberSeparator; using globalFunctions::numberToWxString; - //m_bitmapPreview->SetBitmap(*GlobalResources::getInstance().bitmapSync); - m_buttonStartSync->setBitmapFront(*GlobalResources::getInstance().bitmapStartSync); - m_bitmapCreate->SetBitmap(*GlobalResources::getInstance().bitmapCreate); - m_bitmapUpdate->SetBitmap(*GlobalResources::getInstance().bitmapUpdate); - m_bitmapDelete->SetBitmap(*GlobalResources::getInstance().bitmapDelete); - m_bitmapData->SetBitmap(*GlobalResources::getInstance().bitmapData); + m_buttonStartSync->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("startSync"))); + m_bitmapCreate->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("create"))); + m_bitmapUpdate->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("update"))); + m_bitmapDelete->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("delete"))); + m_bitmapData->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("data"))); m_staticTextVariant->SetLabel(variantName); m_textCtrlData->SetValue(FreeFileSync::formatFilesizeToShortString(statistics.getDataToProcess())); @@ -657,9 +667,9 @@ CompareCfgDialog::CompareCfgDialog(wxWindow* parentWindow, const wxPoint& positi //move dialog up so that compare-config button and first config-variant are on same level Move(wxPoint(position.x, std::max(0, position.y - (m_buttonTimeSize->GetScreenPosition() - GetScreenPosition()).y))); - m_bpButtonHelp->SetBitmapLabel(*GlobalResources::getInstance().bitmapHelp); - m_bitmapByTime->SetBitmap(*GlobalResources::getInstance().bitmapCmpByTime); - m_bitmapByContent->SetBitmap(*GlobalResources::getInstance().bitmapCmpByContent); + m_bpButtonHelp->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("help"))); + m_bitmapByTime->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("cmpByTime"))); + m_bitmapByContent->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("cmpByContent"))); switch (cmpVar) { @@ -714,17 +724,17 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* window, xmlAccess::XmlGlobalSetti GlobalSettingsDlgGenerated(window), settings(globalSettings) { - m_bitmapSettings->SetBitmap(*GlobalResources::getInstance().bitmapSettings); - m_buttonResetDialogs->setBitmapFront(*GlobalResources::getInstance().bitmapWarningSmall, 5); - m_bpButtonAddRow->SetBitmapLabel(*GlobalResources::getInstance().bitmapAddFolderPair); - m_bpButtonRemoveRow->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); + m_bitmapSettings->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("settings"))); + m_buttonResetDialogs->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("warningSmall")), 5); + m_bpButtonAddRow->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); + m_bpButtonRemoveRow->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); m_checkBoxIgnoreOneHour->SetValue(globalSettings.ignoreOneHourDiff); m_checkBoxCopyLocked->SetValue(globalSettings.copyLockedFiles); #ifndef FFS_WIN -m_staticTextCopyLocked->Hide(); -m_checkBoxCopyLocked->Hide(); + m_staticTextCopyLocked->Hide(); + m_checkBoxCopyLocked->Hide(); #endif set(globalSettings.gui.externelApplications); @@ -1130,11 +1140,11 @@ void SyncStatus::updateStatusDialogNow() break; case COMPARING_CONTENT: minimizedToSysTray->setToolTip(wxString(wxT("FreeFileSync - ")) + wxString(_("Comparing content...")) + wxT(" ") + - fromatPercentage(currentData, totalData)); + fromatPercentage(currentData, totalData), currentData.ToDouble() * 100 / totalData.ToDouble()); break; case SYNCHRONIZING: minimizedToSysTray->setToolTip(wxString(wxT("FreeFileSync - ")) + wxString(_("Synchronizing...")) + wxT(" ") + - fromatPercentage(currentData, totalData)); + fromatPercentage(currentData, totalData), currentData.ToDouble() * 100 / totalData.ToDouble()); break; case ABORTED: case FINISHED_WITH_SUCCESS: @@ -1230,37 +1240,37 @@ void SyncStatus::setCurrentStatus(SyncStatusID id) switch (id) { case ABORTED: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusError); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusError"))); m_staticTextStatus->SetLabel(_("Aborted")); break; case FINISHED_WITH_SUCCESS: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusSuccess); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusSuccess"))); m_staticTextStatus->SetLabel(_("Completed")); break; case FINISHED_WITH_ERROR: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusWarning); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusWarning"))); m_staticTextStatus->SetLabel(_("Completed")); break; case PAUSE: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusPause); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusPause"))); m_staticTextStatus->SetLabel(_("Paused")); break; case SCANNING: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusScanning); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusScanning"))); m_staticTextStatus->SetLabel(_("Scanning...")); break; case COMPARING_CONTENT: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusBinCompare); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusBinaryCompare"))); m_staticTextStatus->SetLabel(_("Comparing content...")); break; case SYNCHRONIZING: - m_bitmapStatus->SetBitmap(*GlobalResources::getInstance().bitmapStatusSyncing); + m_bitmapStatus->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("statusSyncing"))); m_staticTextStatus->SetLabel(_("Synchronizing...")); break; } diff --git a/ui/batchStatusHandler.cpp b/ui/batchStatusHandler.cpp index 43e818ee..793f18fd 100644 --- a/ui/batchStatusHandler.cpp +++ b/ui/batchStatusHandler.cpp @@ -63,14 +63,18 @@ private: using namespace globalFunctions; //create logfile directory - const wxString logfileDir = logfileDirectory.empty() ? FreeFileSync::getDefaultLogDirectory() : logfileDirectory; - if (!FreeFileSync::dirExists(wxToZ(logfileDir))) - FreeFileSync::createDirectory(wxToZ(logfileDir)); //create recursively if necessary: may throw (FileError&) + Zstring logfileDir = logfileDirectory.empty() ? + wxToZ(FreeFileSync::getDefaultLogDirectory()) : + FreeFileSync::getFormattedDirectoryName(wxToZ(logfileDirectory)); + + if (!FreeFileSync::dirExists(logfileDir)) + FreeFileSync::createDirectory(logfileDir); //create recursively if necessary: may throw (FileError&) //assemble logfile name - wxString logfileName = logfileDir; - if (!logfileName.empty() && logfileName.Last() != FILE_NAME_SEPARATOR) - logfileName += FILE_NAME_SEPARATOR; + if (!logfileDir.EndsWith(FILE_NAME_SEPARATOR)) + logfileDir += FILE_NAME_SEPARATOR; + + wxString logfileName = zToWx(logfileDir); wxString timeNow = wxDateTime::Now().FormatISOTime(); timeNow.Replace(wxT(":"), wxT("-")); diff --git a/ui/checkVersion.cpp b/ui/checkVersion.cpp index 2fb57ec6..9ecb8876 100644 --- a/ui/checkVersion.cpp +++ b/ui/checkVersion.cpp @@ -1,12 +1,12 @@ #include "checkVersion.h" - +#include <wx/msgdlg.h> #include <wx/protocol/http.h> #include <wx/sstream.h> #include "../version/version.h" -#include <wx/msgdlg.h> #include <wx/utils.h> #include <wx/timer.h> #include "../shared/globalFunctions.h" +#include "smallDialogs.h" class CloseConnectionOnExit @@ -112,9 +112,15 @@ void FreeFileSync::checkForUpdatePeriodically(long& lastUpdateCheck) { if (lastUpdateCheck == 0) { - const int rv = wxMessageBox(_("Do you want FreeFileSync to automatically check for updates every week?"), _("Information"), wxYES_NO | wxICON_QUESTION); - if (rv == wxYES) - { + QuestionDlg* const messageDlg = new QuestionDlg(NULL, + QuestionDlg::BUTTON_YES | QuestionDlg::BUTTON_CANCEL, + wxString(_("Do you want FreeFileSync to automatically check for updates every week?")) + wxT("\n") + + _("(Requires an Internet connection!)")); + + const bool checkRegularly = messageDlg->ShowModal() == QuestionDlg::BUTTON_YES; + messageDlg->Destroy(); + if (checkRegularly) + { lastUpdateCheck = 123; //some old date (few seconds after 1970) checkForUpdatePeriodically(lastUpdateCheck); //check for updates now @@ -140,6 +146,3 @@ void FreeFileSync::checkForUpdatePeriodically(long& lastUpdateCheck) } } - - - diff --git a/ui/folderPair.h b/ui/folderPair.h index 557f3cc6..a67e5078 100644 --- a/ui/folderPair.h +++ b/ui/folderPair.h @@ -60,13 +60,13 @@ public: { if (altSyncConfig.get()) { - basicPanel_.m_bpButtonAltSyncCfg->SetBitmapLabel(*GlobalResources::getInstance().bitmapSyncCfgSmall); + basicPanel_.m_bpButtonAltSyncCfg->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("syncConfigSmall"))); basicPanel_.m_bpButtonAltSyncCfg->SetToolTip(wxString(_("Select alternate synchronization settings")) + wxT(" ") + globalFunctions::LINE_BREAK + wxT("(") + altSyncConfig->syncConfiguration.getVariantName() + wxT(")")); } else { - basicPanel_.m_bpButtonAltSyncCfg->SetBitmapLabel(*GlobalResources::getInstance().bitmapSyncCfgSmallGrey); + basicPanel_.m_bpButtonAltSyncCfg->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("syncConfigSmallGrey"))); basicPanel_.m_bpButtonAltSyncCfg->SetToolTip(_("Select alternate synchronization settings")); } @@ -77,18 +77,18 @@ public: const bool isNullFilter = NameFilter(localFilter.includeFilter, localFilter.excludeFilter).isNull(); if (isNullFilter) { - basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterSmallGrey); + basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterSmallGrey"))); basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("No filter selected")); } else { - basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterSmall); + basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterSmall"))); basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("Filter has been selected")); } } else { - basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(*GlobalResources::getInstance().bitmapFilterSmallGrey); + basicPanel_.m_bpButtonLocalFilter->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("filterSmallGrey"))); basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("Filtering is deactivated")); } } @@ -104,7 +104,7 @@ protected: basicPanel_.m_bpButtonAltSyncCfg-> Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FolderPairPanelBasic::OnAltSyncCfg), NULL, this); basicPanel_.m_bpButtonLocalFilter->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FolderPairPanelBasic::OnLocalFilterCfg), NULL, this); - basicPanel_.m_bpButtonRemovePair->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); + basicPanel_.m_bpButtonRemovePair->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); } virtual void OnLocalFilterCfgRemoveConfirm(wxCommandEvent& event) diff --git a/ui/gridView.cpp b/ui/gridView.cpp index 8a3929fb..9b841e56 100644 --- a/ui/gridView.cpp +++ b/ui/gridView.cpp @@ -92,15 +92,11 @@ GridView::StatusCmpResult GridView::updateCmpResult(bool hideFiltered, //maps so } else { - const DirMapping* dirObj = dynamic_cast<const DirMapping*>(fsObj); - if (dirObj) - { - if (!dirObj->isEmpty<LEFT_SIDE>()) + if (!fsObj->isEmpty<LEFT_SIDE>()) ++output.foldersOnLeftView; - if (!dirObj->isEmpty<RIGHT_SIDE>()) + if (!fsObj->isEmpty<RIGHT_SIDE>()) ++output.foldersOnRightView; - } } viewRef.push_back(*j); @@ -119,6 +115,7 @@ GridView::StatusSyncPreview::StatusSyncPreview() : existsSyncDirLeft(false), existsSyncDirRight(false), existsSyncDirNone(false), + existsSyncEqual(false), existsConflict(false), filesOnLeftView(0), @@ -135,6 +132,7 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map bool syncDirOverwLeftActive, bool syncDirOverwRightActive, bool syncDirNoneActive, + bool syncEqualActive, bool conflictFilesActive) { StatusSyncPreview output; @@ -146,13 +144,6 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map const FileSystemObject* fsObj = getReferencedRow(*j); if (fsObj) { - //synchronization preview - - //exclude result "==" -//#warning na dann consider mal! - if (fsObj->getCategory() == FILE_EQUAL) //note: consider "objectsTotal" - continue; - //hide filtered row, if corresponding option is set if (hideFiltered && !fsObj->isActive()) continue; @@ -188,6 +179,10 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map output.existsSyncDirNone = true; if (!syncDirNoneActive) continue; break; + case SO_EQUAL: + output.existsSyncEqual = true; + if (!syncEqualActive) continue; + break; case SO_UNRESOLVED_CONFLICT: output.existsConflict = true; if (!conflictFilesActive) continue; @@ -211,15 +206,11 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map } else { - const DirMapping* dirObj = dynamic_cast<const DirMapping*>(fsObj); - if (dirObj) - { - if (!dirObj->isEmpty<LEFT_SIDE>()) + if (!fsObj->isEmpty<LEFT_SIDE>()) ++output.foldersOnLeftView; - if (!dirObj->isEmpty<RIGHT_SIDE>()) + if (!fsObj->isEmpty<RIGHT_SIDE>()) ++output.foldersOnRightView; - } } viewRef.push_back(*j); diff --git a/ui/gridView.h b/ui/gridView.h index 5ab28a44..eaa8ad8c 100644 --- a/ui/gridView.h +++ b/ui/gridView.h @@ -61,6 +61,7 @@ public: bool existsSyncDirLeft; bool existsSyncDirRight; bool existsSyncDirNone; + bool existsSyncEqual; bool existsConflict; unsigned int filesOnLeftView; @@ -81,6 +82,7 @@ public: bool syncDirOverwLeftActive, bool syncDirOverwRightActive, bool syncDirNoneActive, + bool syncEqualActive, bool conflictFilesActive); @@ -125,7 +127,7 @@ private: // | // | (update...) // \|/ - std::vector<RefIndex> sortedRef; //equivalent to folerCmp, but may be sorted + std::vector<RefIndex> sortedRef; //equivalent to folderCmp, but may be sorted // | // | (setData) // \|/ diff --git a/ui/guiGenerated.cpp b/ui/guiGenerated.cpp index 9670c775..c522ccff 100644 --- a/ui/guiGenerated.cpp +++ b/ui/guiGenerated.cpp @@ -492,6 +492,15 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const sbSizer31->Add( 0, 0, 1, wxEXPAND, 5 ); + m_bpButtonSyncCreateLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncCreateLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonSyncDirOverwLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDirOverwLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonSyncDeleteLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDeleteLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonLeftOnly = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -504,24 +513,15 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonDifferent = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonSyncDirNone = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDirNone, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonRightNewer = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonRightOnly = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonSyncCreateLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); - sbSizer31->Add( m_bpButtonSyncCreateLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - m_bpButtonSyncDirOverwLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); - sbSizer31->Add( m_bpButtonSyncDirOverwLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - m_bpButtonSyncDeleteLeft = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); - sbSizer31->Add( m_bpButtonSyncDeleteLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - m_bpButtonSyncDirNone = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); - sbSizer31->Add( m_bpButtonSyncDirNone, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButtonSyncDeleteRight = new ToggleButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonSyncDeleteRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -756,16 +756,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxActivateFilter->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); m_checkBoxHideFilt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), 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_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_bpButtonSyncDirNone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), 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 ); @@ -817,16 +817,16 @@ MainDialogGenerated::~MainDialogGenerated() m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxActivateFilter->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); m_checkBoxHideFilt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), 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_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_bpButtonSyncDirNone->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), 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 ); @@ -1309,7 +1309,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS wxBoxSizer* bSizer1151; bSizer1151 = new wxBoxSizer( wxHORIZONTAL ); - m_textCtrlCustomDelFolder = new wxTextCtrl( m_panelCustomDeletionDir, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_RIGHT ); + m_textCtrlCustomDelFolder = new wxTextCtrl( m_panelCustomDeletionDir, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_textCtrlCustomDelFolder->SetMinSize( wxSize( 160,-1 ) ); bSizer1151->Add( m_textCtrlCustomDelFolder, 1, wxALIGN_CENTER_VERTICAL, 5 ); @@ -3322,7 +3322,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w wxBoxSizer* bSizer66; bSizer66 = new wxBoxSizer( wxHORIZONTAL ); - m_staticText181 = new wxStaticText( m_panel13, wxID_ANY, _("Include: *.doc;*.zip;*.exe\nExclude: temp\\*"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText181 = new wxStaticText( m_panel13, wxID_ANY, _("Include: *.doc;*.zip;*.exe\nExclude: \\stuff\\temp\\*"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText181->Wrap( -1 ); bSizer66->Add( m_staticText181, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); @@ -3600,7 +3600,7 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_staticTextCopyLocked = new wxStaticText( this, wxID_ANY, _("Copy locked files"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextCopyLocked->Wrap( -1 ); - m_staticTextCopyLocked->SetToolTip( _("Use Volume Shadow Copy Service to copy locked or shared files.") ); + m_staticTextCopyLocked->SetToolTip( _("Copy shared or locked files using Volume Shadow Copy Service.") ); bSizer1201->Add( m_staticTextCopyLocked, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -3609,7 +3609,7 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_checkBoxCopyLocked = new wxCheckBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxCopyLocked->SetToolTip( _("Use Volume Shadow Copy Service to copy locked or shared files.") ); + m_checkBoxCopyLocked->SetToolTip( _("Copy shared or locked files using Volume Shadow Copy Service.") ); bSizer1201->Add( m_checkBoxCopyLocked, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -3663,7 +3663,7 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_gridCustomCommand->EnableDragColSize( true ); m_gridCustomCommand->SetColLabelSize( 20 ); m_gridCustomCommand->SetColLabelValue( 0, _("Description") ); - m_gridCustomCommand->SetColLabelValue( 1, _("Commandline") ); + m_gridCustomCommand->SetColLabelValue( 1, _("Command line") ); m_gridCustomCommand->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows diff --git a/ui/guiGenerated.h b/ui/guiGenerated.h index 70cce976..ab4d3c12 100644 --- a/ui/guiGenerated.h +++ b/ui/guiGenerated.h @@ -118,16 +118,16 @@ class MainDialogGenerated : public wxFrame wxCheckBox* m_checkBoxHideFilt; wxPanel* m_panel112; + 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_bpButtonSyncCreateLeft; - ToggleButton* m_bpButtonSyncDirOverwLeft; - ToggleButton* m_bpButtonSyncDeleteLeft; - ToggleButton* m_bpButtonSyncDirNone; ToggleButton* m_bpButtonSyncDeleteRight; ToggleButton* m_bpButtonSyncDirOverwRight; ToggleButton* m_bpButtonSyncCreateRight; @@ -195,16 +195,16 @@ class MainDialogGenerated : public wxFrame virtual void OnConfigureFilter( wxCommandEvent& event ){ event.Skip(); } virtual void OnFilterButton( wxCommandEvent& event ){ event.Skip(); } virtual void OnHideFilteredButton( 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 OnSyncCreateLeft( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncDirLeft( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncDeleteLeft( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncDirNone( 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(); } diff --git a/ui/settingsDialog.cpp b/ui/settingsDialog.cpp index 230d187d..fe037322 100644 --- a/ui/settingsDialog.cpp +++ b/ui/settingsDialog.cpp @@ -48,12 +48,12 @@ SyncCfgDialog::SyncCfgDialog(wxWindow* window, updateConfigIcons(cmpVariant, localSyncConfiguration); //set icons for this dialog - m_bitmapLeftOnly->SetBitmap(*GlobalResources::getInstance().bitmapLeftOnly); - m_bitmapRightOnly->SetBitmap(*GlobalResources::getInstance().bitmapRightOnly); - m_bitmapLeftNewer->SetBitmap(*GlobalResources::getInstance().bitmapLeftNewer); - m_bitmapRightNewer->SetBitmap(*GlobalResources::getInstance().bitmapRightNewer); - m_bitmapDifferent->SetBitmap(*GlobalResources::getInstance().bitmapDifferent); - m_bitmapConflict->SetBitmap(*GlobalResources::getInstance().bitmapConflictGrey); + m_bitmapLeftOnly->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("leftOnly"))); + m_bitmapRightOnly->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("rightOnly"))); + m_bitmapLeftNewer->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("leftNewer"))); + m_bitmapRightNewer->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("rightNewer"))); + m_bitmapDifferent->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("different"))); + m_bitmapConflict->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("conflictGrey"))); bSizer201->Layout(); //wxButtonWithImage size might have changed @@ -175,15 +175,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.exLeftSideOnly) { case SYNC_DIR_RIGHT: - buttonLeftOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowRightCr); + buttonLeftOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowRightCr"))); buttonLeftOnly->SetToolTip(getDescription(SO_CREATE_NEW_RIGHT)); break; case SYNC_DIR_LEFT: - buttonLeftOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapDeleteLeft); + buttonLeftOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("deleteLeft"))); buttonLeftOnly->SetToolTip(getDescription(SO_DELETE_LEFT)); break; case SYNC_DIR_NONE: - buttonLeftOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowNone); + buttonLeftOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowNone"))); buttonLeftOnly->SetToolTip(getDescription(SO_DO_NOTHING)); break; } @@ -191,15 +191,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.exRightSideOnly) { case SYNC_DIR_RIGHT: - buttonRightOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapDeleteRight); + buttonRightOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("deleteRight"))); buttonRightOnly->SetToolTip(getDescription(SO_DELETE_RIGHT)); break; case SYNC_DIR_LEFT: - buttonRightOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowLeftCr); + buttonRightOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowLeftCr"))); buttonRightOnly->SetToolTip(getDescription(SO_CREATE_NEW_LEFT)); break; case SYNC_DIR_NONE: - buttonRightOnly->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowNone); + buttonRightOnly->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowNone"))); buttonRightOnly->SetToolTip(getDescription(SO_DO_NOTHING)); break; } @@ -207,15 +207,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.leftNewer) { case SYNC_DIR_RIGHT: - buttonLeftNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowRight); + buttonLeftNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowRight"))); buttonLeftNewer->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: - buttonLeftNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowLeft); + buttonLeftNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowLeft"))); buttonLeftNewer->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: - buttonLeftNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowNone); + buttonLeftNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowNone"))); buttonLeftNewer->SetToolTip(getDescription(SO_DO_NOTHING)); break; } @@ -223,15 +223,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.rightNewer) { case SYNC_DIR_RIGHT: - buttonRightNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowRight); + buttonRightNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowRight"))); buttonRightNewer->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: - buttonRightNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowLeft); + buttonRightNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowLeft"))); buttonRightNewer->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: - buttonRightNewer->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowNone); + buttonRightNewer->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowNone"))); buttonRightNewer->SetToolTip(getDescription(SO_DO_NOTHING)); break; } @@ -239,15 +239,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.different) { case SYNC_DIR_RIGHT: - buttonDifferent->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowRight); + buttonDifferent->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowRight"))); buttonDifferent->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: - buttonDifferent->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowLeft); + buttonDifferent->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowLeft"))); buttonDifferent->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: - buttonDifferent->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowNone); + buttonDifferent->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowNone"))); buttonDifferent->SetToolTip(getDescription(SO_DO_NOTHING)); break; } @@ -255,15 +255,15 @@ void SyncCfgDialog::updateConfigIcons(const CompareVariant compareVar, switch (syncConfig.conflict) { case SYNC_DIR_RIGHT: - buttonConflict->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowRight); + buttonConflict->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowRight"))); buttonConflict->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: - buttonConflict->SetBitmapLabel(*GlobalResources::getInstance().bitmapArrowLeft); + buttonConflict->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("arrowLeft"))); buttonConflict->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: - buttonConflict->SetBitmapLabel(*GlobalResources::getInstance().bitmapConflict); + buttonConflict->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("conflict"))); buttonConflict->SetToolTip(_("Leave as unresolved conflict")); break; } @@ -350,7 +350,7 @@ void updateToolTipDeletionHandling(wxChoice* choiceHandleError, wxPanel* customD break; case FreeFileSync::MOVE_TO_CUSTOM_DIRECTORY: - choiceHandleError->SetToolTip(_("Move files to a user-defined directory.")); + choiceHandleError->SetToolTip(_("Move files into a time-stamped subdirectory.")); customDir->Enable(); break; } @@ -637,16 +637,16 @@ void BatchDialog::init() //set icons for this dialog - m_bpButtonAddPair->SetBitmapLabel(*GlobalResources::getInstance().bitmapAddFolderPair); - m_bitmapLeftOnly->SetBitmap(*GlobalResources::getInstance().bitmapLeftOnly); - m_bitmapRightOnly->SetBitmap(*GlobalResources::getInstance().bitmapRightOnly); - m_bitmapLeftNewer->SetBitmap(*GlobalResources::getInstance().bitmapLeftNewer); - m_bitmapRightNewer->SetBitmap(*GlobalResources::getInstance().bitmapRightNewer); - m_bitmapDifferent->SetBitmap(*GlobalResources::getInstance().bitmapDifferent); - m_bitmapConflict->SetBitmap(*GlobalResources::getInstance().bitmapConflictGrey); - m_bitmap8->SetBitmap(*GlobalResources::getInstance().bitmapInclude); - m_bitmap9->SetBitmap(*GlobalResources::getInstance().bitmapExclude); - m_bitmap27->SetBitmap(*GlobalResources::getInstance().bitmapBatch); + m_bpButtonAddPair->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); + m_bitmapLeftOnly->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("leftOnly"))); + m_bitmapRightOnly->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("rightOnly"))); + m_bitmapLeftNewer->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("leftNewer"))); + m_bitmapRightNewer->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("rightNewer"))); + m_bitmapDifferent->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("different"))); + m_bitmapConflict->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("conflictGrey"))); + m_bitmap8->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("include"))); + m_bitmap9->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("exclude"))); + m_bitmap27->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("batch"))); m_buttonSave->SetFocus(); } @@ -1143,11 +1143,11 @@ void BatchDialog::OnAddFolderPair(wxCommandEvent& event) addFolderPair(newPairs, true); //add pair in front of additonal pairs //clear first pair - const FolderPairEnh cfgEmpty; - firstFolderPair->setValues(cfgEmpty.leftDirectory, - cfgEmpty.rightDirectory, - cfgEmpty.altSyncConfig, - cfgEmpty.localFilter); + const FolderPairEnh cfgEmpty; + firstFolderPair->setValues(cfgEmpty.leftDirectory, + cfgEmpty.rightDirectory, + cfgEmpty.altSyncConfig, + cfgEmpty.localFilter); } @@ -1220,48 +1220,48 @@ void BatchDialog::addFolderPair(const std::vector<FreeFileSync::FolderPairEnh>& wxWindowUpdateLocker dummy(m_panelOverview); //avoid display distortion if (!newPairs.empty()) -{ - //add folder pairs - int pairHeight = 0; - for (std::vector<FreeFileSync::FolderPairEnh>::const_iterator i = newPairs.begin(); i != newPairs.end(); ++i) { - BatchFolderPairPanel* newPair = new BatchFolderPairPanel(m_scrolledWindow6, *this); - - if (addFront) + //add folder pairs + int pairHeight = 0; + for (std::vector<FreeFileSync::FolderPairEnh>::const_iterator i = newPairs.begin(); i != newPairs.end(); ++i) { - bSizerAddFolderPairs->Insert(0, newPair, 0, wxEXPAND, 5); - additionalFolderPairs.insert(additionalFolderPairs.begin(), newPair); - } - else - { - bSizerAddFolderPairs->Add(newPair, 0, wxEXPAND, 5); - additionalFolderPairs.push_back(newPair); - } + BatchFolderPairPanel* newPair = new BatchFolderPairPanel(m_scrolledWindow6, *this); - //get size of scrolled window - pairHeight = newPair->GetSize().GetHeight(); + if (addFront) + { + bSizerAddFolderPairs->Insert(0, newPair, 0, wxEXPAND, 5); + additionalFolderPairs.insert(additionalFolderPairs.begin(), newPair); + } + else + { + bSizerAddFolderPairs->Add(newPair, 0, wxEXPAND, 5); + additionalFolderPairs.push_back(newPair); + } - //register events - newPair->m_bpButtonRemovePair->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BatchDialog::OnRemoveFolderPair), NULL, this ); + //get size of scrolled window + pairHeight = newPair->GetSize().GetHeight(); - //set alternate configuration - newPair->setValues(i->leftDirectory, - i->rightDirectory, - i->altSyncConfig, - i->localFilter); - } - //set size of scrolled window - const int visiblePairs = std::min(additionalFolderPairs.size() + 1, MAX_FOLDER_PAIRS); //up to MAX_FOLDER_PAIRS pairs shall be shown - m_scrolledWindow6->SetMinSize(wxSize( -1, pairHeight * visiblePairs)); + //register events + newPair->m_bpButtonRemovePair->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BatchDialog::OnRemoveFolderPair), NULL, this ); - //update controls - m_scrolledWindow6->Fit(); //adjust scrolled window size - m_panelOverview->Layout(); //adjust stuff inside scrolled window - Fit(); //adapt dialog size + //set alternate configuration + newPair->setValues(i->leftDirectory, + i->rightDirectory, + i->altSyncConfig, + i->localFilter); + } + //set size of scrolled window + const int visiblePairs = std::min(additionalFolderPairs.size() + 1, MAX_FOLDER_PAIRS); //up to MAX_FOLDER_PAIRS pairs shall be shown + m_scrolledWindow6->SetMinSize(wxSize( -1, pairHeight * visiblePairs)); - //after changing folder pairs window focus is lost: results in scrolled window scrolling to top each time window is shown: we don't want this - m_bpButtonLeftOnly->SetFocus(); -} + //update controls + m_scrolledWindow6->Fit(); //adjust scrolled window size + m_panelOverview->Layout(); //adjust stuff inside scrolled window + Fit(); //adapt dialog size + + //after changing folder pairs window focus is lost: results in scrolled window scrolling to top each time window is shown: we don't want this + m_bpButtonLeftOnly->SetFocus(); + } updateGuiForFolderPair(); } @@ -1269,7 +1269,7 @@ void BatchDialog::addFolderPair(const std::vector<FreeFileSync::FolderPairEnh>& void BatchDialog::removeAddFolderPair(const int pos) { - wxWindowUpdateLocker dummy(m_panelOverview); //avoid display distortion + wxWindowUpdateLocker dummy(m_panelOverview); //avoid display distortion if (0 <= pos && pos < static_cast<int>(additionalFolderPairs.size())) { @@ -1296,7 +1296,7 @@ void BatchDialog::removeAddFolderPair(const int pos) m_bpButtonLeftOnly->SetFocus(); } - updateGuiForFolderPair(); + updateGuiForFolderPair(); } diff --git a/ui/settingsDialog.h b/ui/settingsDialog.h index 0864cf92..15d880f4 100644 --- a/ui/settingsDialog.h +++ b/ui/settingsDialog.h @@ -137,7 +137,7 @@ private: void removeAddFolderPair(const int pos); void clearAddFolderPairs(); -void updateGuiForFolderPair(); + void updateGuiForFolderPair(); FreeFileSync::CompareVariant getCurrentCompareVar() const; diff --git a/ui/sorting.h b/ui/sorting.h index 04ecc171..5771d7db 100644 --- a/ui/sorting.h +++ b/ui/sorting.h @@ -60,16 +60,16 @@ bool sortByFileName(const FileSystemObject& a, const FileSystemObject& b) return true; //empty rows always last - if (dynamic_cast<const DirMapping*>(&a)) //sort directories by relative name + if (isDirectoryMapping(a)) //sort directories by relative name { - if (dynamic_cast<const DirMapping*>(&b)) + if (isDirectoryMapping(b)) return stringSmallerThan(a.getRelativeName<side>(), b.getRelativeName<side>()); else return false; } else { - if (dynamic_cast<const DirMapping*>(&b)) + if (isDirectoryMapping(b)) return true; else return Compare<ascending>().isSmallerThan( @@ -86,15 +86,16 @@ bool sortByRelativeName(const FileSystemObject& a, const FileSystemObject& b) else if (b.isEmpty<side>()) return true; //empty rows always last - const FileMapping* fileObjA = dynamic_cast<const FileMapping*>(&a); - const Zstring relDirNameA = fileObjA != NULL ? - a.getParentRelativeName() : //file - a.getRelativeName<side>(); //directory + const bool isDirectoryA = isDirectoryMapping(a); + const Zstring relDirNameA = isDirectoryA ? + a.getRelativeName<side>() : //directory + a.getParentRelativeName(); //file + + const bool isDirectoryB = isDirectoryMapping(b); + const Zstring relDirNameB = isDirectoryB ? + b.getRelativeName<side>() : //directory + b.getParentRelativeName(); //file - const FileMapping* fileObjB = dynamic_cast<const FileMapping*>(&b); - const Zstring relDirNameB = fileObjB != NULL ? - b.getParentRelativeName() : //file - b.getRelativeName<side>(); //directory //compare relative names without filenames first const int rv = compareString(relDirNameA, relDirNameB); @@ -102,9 +103,9 @@ bool sortByRelativeName(const FileSystemObject& a, const FileSystemObject& b) return Compare<ascending>().isSmallerThan(rv, 0); else //compare the filenames { - if (fileObjB == NULL) //directories shall appear before files + if (isDirectoryB) //directories shall appear before files return false; - else if (fileObjA == NULL) + else if (isDirectoryA) return true; return stringSmallerThan(a.getShortName<side>(), b.getShortName<side>()); diff --git a/ui/trayIcon.cpp b/ui/trayIcon.cpp index 478d135a..921fe79f 100644 --- a/ui/trayIcon.cpp +++ b/ui/trayIcon.cpp @@ -1,8 +1,8 @@ #include "trayIcon.h" #include "../library/resources.h" #include "smallDialogs.h" -//#include "../library/statusHandler.h" #include <wx/taskbar.h> +#include <cmath> enum Selection @@ -89,10 +89,90 @@ void MinimizeToTray::resumeFromTray() //remove trayIcon and restore windows: Mi } -void MinimizeToTray::setToolTip(const wxString& toolTipText) +namespace +{ +inline +int roundNum(double d) //little rounding function +{ + return static_cast<int>(d < 0 ? d - .5 : d + .5); +} + + +wxIcon generateIcon(size_t percent) //generate icon with progress indicator +{ + percent = std::min(percent, static_cast<size_t>(100u)); //handle invalid input + +#ifdef FFS_WIN + static const wxBitmap trayIcon = GlobalResources::getInstance().getImageByName(wxT("FFS_tray_win.png")); +#elif defined FFS_LINUX + static const wxBitmap trayIcon = GlobalResources::getInstance().getImageByName(wxT("FFS_tray_linux.png")); +#endif + + const int indicatorHeight = roundNum((trayIcon.GetHeight() * percent) / 100.0); + + //minor optimization + static std::pair<int, wxIcon> buffer = std::make_pair(-1, wxNullIcon); + if (buffer.first == indicatorHeight) + return buffer.second; + + if ( trayIcon.GetWidth() > 0 && + trayIcon.GetHeight() > 0) + { + static const int indicatorWidth = trayIcon.GetWidth() * .25; + const int indicatorXBegin = ceil((trayIcon.GetWidth() - indicatorWidth) / 2.0); + const int indicatorYBegin = trayIcon.GetHeight() - indicatorHeight; + + wxImage genImage(trayIcon.ConvertToImage()); + + //draw progress indicator: do NOT use wxDC::DrawRectangle! Doesn't respect alpha in Windows, but does in Linux! + //We need a simple, working solution: + unsigned char* const data = genImage.GetData(); + for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row) + { + for (int col = indicatorXBegin; col < indicatorXBegin + indicatorWidth; ++col) + { + unsigned char* const pixelBegin = data + (row * genImage.GetWidth() + col) * 3; + pixelBegin[0] = 255; //red + pixelBegin[1] = 255; //green + pixelBegin[2] = 0; //blue + } + } + + if (genImage.HasAlpha()) + { + unsigned char* const alpha = genImage.GetAlpha(); + //make progress indicator fully opaque: + for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row) + ::memset(alpha + row * genImage.GetWidth() + indicatorXBegin, wxIMAGE_ALPHA_OPAQUE, indicatorWidth); + } + + wxIcon genIcon; + genIcon.CopyFromBitmap(wxBitmap(genImage)); + + //fill buffer + buffer.first = indicatorHeight; + buffer.second = genIcon; + + return genIcon; + } + + //fallback + wxIcon defaultIcon; + defaultIcon.CopyFromBitmap(trayIcon); + + //fill buffer + buffer.first = indicatorHeight; + buffer.second = defaultIcon; + + return defaultIcon; +} +} + + +void MinimizeToTray::setToolTip(const wxString& toolTipText, size_t percent) { if (trayIcon) - trayIcon->SetIcon(*GlobalResources::getInstance().programIcon, toolTipText); + trayIcon->SetIcon(generateIcon(percent), toolTipText); } @@ -125,3 +205,4 @@ void MinimizeToTray::OnDoubleClick(wxCommandEvent& event) { resumeFromTray(); } + diff --git a/ui/trayIcon.h b/ui/trayIcon.h index 94e75518..8c8797d4 100644 --- a/ui/trayIcon.h +++ b/ui/trayIcon.h @@ -11,7 +11,7 @@ public: MinimizeToTray(wxTopLevelWindow* callerWnd, wxWindow* secondWnd = NULL); //ensure callerWind has longer lifetime! ~MinimizeToTray(); //show windows again - void setToolTip(const wxString& toolTipText); + void setToolTip(const wxString& toolTipText, size_t percent = 0); //percent (optional), number between [0, 100], for small progress indicator void keepHidden(); //do not show windows again: avoid window flashing shortly before it is destroyed private: diff --git a/version/version.h b/version/version.h index 647be5ba..6f9095ce 100644 --- a/version/version.h +++ b/version/version.h @@ -2,5 +2,5 @@ namespace FreeFileSync { - static const wxString currentVersion = wxT("3.2"); //internal linkage! + static const wxString currentVersion = wxT("3.3"); //internal linkage! } |