diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:08:42 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:08:42 +0200 |
commit | c32707148292d104c66276b43796d6057c8c7a5d (patch) | |
tree | bb83513f4aff24153e21a4ec92e34e4c27651b1f | |
parent | 3.9 (diff) | |
download | FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.tar.gz FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.tar.bz2 FreeFileSync-c32707148292d104c66276b43796d6057c8c7a5d.zip |
3.10
153 files changed, 5142 insertions, 3784 deletions
diff --git a/Application.cpp b/Application.cpp index 120bd567..af111a65 100644 --- a/Application.cpp +++ b/Application.cpp @@ -102,6 +102,15 @@ void Application::OnStartApplication(wxIdleEvent&) GlobalResources::getInstance().load(); //loads bitmap resources on program startup +#ifndef _MSC_VER +#warning wxWidgets 2.9 +#endif + /* + wxToolTip::SetMaxWidth(-1); //disable tooltip wrapping + wxToolTip::SetAutoPop(7000); //tooltip visibilty in ms, 5s seems to be default for Windows + */ + + try //load global settings from XML { if (fileExists(wxToZ(xmlAccess::getGlobalConfigFile()))) @@ -182,9 +191,10 @@ int Application::OnExit() { xmlAccess::writeConfig(globalSettings); } - catch (const xmlAccess::XmlError& error) + catch (const xmlAccess::XmlError&) { - wxMessageBox(error.msg(), _("Error"), wxOK | wxICON_ERROR); + //wxMessageBox(error.msg(), _("Error"), wxOK | wxICON_ERROR); -> not that important/might be tedious in silent batch? + assert(false); //get info in debug build } return 0; @@ -233,10 +243,9 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet //COMPARE DIRECTORIES ffs3::FolderComparison folderCmp; ffs3::CompareProcess comparison(batchCfg.mainCfg.handleSymlinks, - globSettings.fileTimeTolerance, - globSettings.ignoreOneHourDiff, - globSettings.optDialogs, - statusHandler.get()); + globSettings.fileTimeTolerance, + globSettings.optDialogs, + statusHandler.get()); comparison.startCompareProcess(ffs3::extractCompareCfg(batchCfg.mainCfg), batchCfg.mainCfg.compareVar, @@ -245,7 +254,7 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet //check if there are files/folders to be sync'ed at all if (!synchronizationNeeded(folderCmp)) { - statusHandler->reportInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case + statusHandler->logInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case //return; -> disabled: <automatic> mode requires database to be written in any case } diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt index 693d96fc..97e98126 100644 --- a/BUILD/Changelog.txt +++ b/BUILD/Changelog.txt @@ -2,6 +2,28 @@ |FreeFileSync| -------------- +Changelog v3.10 +--------------- +Automatically solve daylight saving time and time zone shift issues on FAT/FAT32 (finally) +Instantly resolve abandoned directory locks associated with local computer +Show expanded directory name as tooltip and label text (resolves macros and relative paths) +Do not copy relative file attributes for base target directories that are created implicitly +Move dialogs by clicking (almost) anywhere +RealtimeSync: ignore request for device removal on Samba shares +Added UTF-8 BOM for CSV export +Correctly handle window position on multi-screen desktop +Disabled warning "database not yet existing" +RealtimeSync: replaced delay by minimum idle time +Maximum number of folder pairs configurable via GlobalSettings.xml (XML node <FolderPairsMax>) +Added tooltips to display long filenames on main grid +Keep application responsive when deleting large directories +Vista/Windows 7: harmonize modification times shown on main grid with Windows Explorer +Changed background color to avoid unreadable texts in combination with certain color themes +Toggle middle grid comparison result/sync preview with right mouse button click +Further GUI enhancements/polishment/standard conformance +Updated translation files + + Changelog v3.9 -------------- Advanced locking strategy to allow multiple processes synchronize the same directories (e.g. via network share) @@ -31,7 +53,7 @@ Run folder existence checks in separate thread (faster network share access) Write <Automatic> mode database file even if both sides are already in sync Don't raise status dialog to the top after synchronisation Embedded version information into executable (Windows) -Migrated Compiler to Visual C++ 2010 (Windows) +Migrated compiler to Visual C++ 2010 (Windows) Avoid losing manual changes when excluding via context menu Adjusted auto-updater web-address Updated translation files diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm Binary files differindex cfcf6752..381fc7ca 100644 --- a/BUILD/FreeFileSync.chm +++ b/BUILD/FreeFileSync.chm diff --git a/BUILD/Help/FreeFileSync.hhp b/BUILD/Help/FreeFileSync.hhp index 02e45e53..a20a4acd 100644 --- a/BUILD/Help/FreeFileSync.hhp +++ b/BUILD/Help/FreeFileSync.hhp @@ -20,7 +20,7 @@ html\advanced\Ftp.html html\advanced\ScheduleBatch.html html\advanced\SendMail.html html\advanced\SymbolicLinks.html -html\advanced\TimeStamped.html +html\advanced\BackupStrategy.html html\advanced\VariableDrive.html html\Overview.html html\advanced\DaylightSavingTime.html diff --git a/BUILD/Help/Table of Contents.hhc b/BUILD/Help/Table of Contents.hhc index 35ad8d46..1c23acff 100644 --- a/BUILD/Help/Table of Contents.hhc +++ b/BUILD/Help/Table of Contents.hhc @@ -29,11 +29,15 @@ </OBJECT> <UL> <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Backup Strategies"> + <param name="Local" value="html\advanced\BackupStrategy.html"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> <param name="Name" value="Batch Scripting"> <param name="Local" value="html\advanced\Batch Scripting.html"> </OBJECT> <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Compare by filesize"> + <param name="Name" value="Compare by file size"> <param name="Local" value="html\advanced\CompareFileSize.html"> </OBJECT> <LI> <OBJECT type="text/sitemap"> @@ -81,10 +85,6 @@ <param name="Local" value="html\advanced\Ftp.html"> </OBJECT> <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Time-stamped directories"> - <param name="Local" value="html\advanced\TimeStamped.html"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> <param name="Name" value="Variable drive letters"> <param name="Local" value="html\advanced\VariableDrive.html"> </OBJECT> diff --git a/BUILD/Help/html/Unbenannt 1.odf b/BUILD/Help/html/Unbenannt 1.odf Binary files differdeleted file mode 100644 index e51231f5..00000000 --- a/BUILD/Help/html/Unbenannt 1.odf +++ /dev/null diff --git a/BUILD/Help/html/advanced/TimeStamped.html b/BUILD/Help/html/advanced/BackupStrategy.html index 392efea2..c3274e2a 100644 --- a/BUILD/Help/html/advanced/TimeStamped.html +++ b/BUILD/Help/html/advanced/BackupStrategy.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100713;20300500"> + <META NAME="CHANGED" CONTENT="20100902;19191700"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -22,22 +22,36 @@ --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> -<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Create regular -backups with time-stamped directory names</FONT></H3> +<BODY LANG="en-US" DIR="LTR"> +<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Backup strategies</FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">You can -use special macros within directory names that are expanded during -synchronization.</FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>1. +Full backup with versioning of old files</B></FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">In +synchronization settings select and specify a "User-defined +directory" for deletion handling. FreeFileSync will place files +that have been deleted or overwritten with newer versions into +corresponding time-stamped sub directories. This provides a +space-optimized way to retain all older versions of files while the +most recent ones are available in main source and target directories.</FONT></P> +<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>2. +Full backup to different target directories</B></FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">All +directory input fields may contain environment variables and special +macros that are expanded during synchronization. This allows for +complete backups into different target directories.</FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Example:</B></FONT></P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Let's -assume you have a directory "<FONT FACE="Courier New, monospace">C:\Source</FONT>" -which you want to backup each day into a time-stamped target -directory like "<FONT FACE="Courier New, monospace">C:\Target_2009-10-08</FONT>". -All that needs to be done is setting up base directories like these:</FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">A +directory "C:\Source" requires a daily backup into a +time-stamped target directory like "C:\Target_2009-10-08". +Base directories are set up accordingly:</FONT></P> <UL> <P><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> <UL> @@ -58,16 +72,17 @@ errors</I>" to avoid the warning that target directory is not (yet) existing.</FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Overview:</B></FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Macro +overview:</B></FONT></P> <UL> <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">%time% - - </FONT>current time, format [hhmmss], e.g. "<FONT FACE="Courier New, monospace">201340</FONT>"<BR><FONT FACE="Courier New, monospace">%date% - - </FONT>current date, e.g. "<FONT FACE="Courier New, monospace">2010-07-13</FONT>"<BR><FONT FACE="Courier New, monospace">%week% - - </FONT>calendar week, e.g. "<FONT FACE="Courier New, monospace">28</FONT>"<BR><FONT FACE="Courier New, monospace">%month% - - </FONT>current month, e.g. "<FONT FACE="Courier New, monospace">July</FONT>"<BR><FONT FACE="Courier New, monospace">%year% - - </FONT>current year, e.g. "<FONT FACE="Courier New, monospace">2010</FONT>"</FONT></P> + </FONT>current time, format [hhmmss], e. g. "<FONT FACE="Courier New, monospace">201340</FONT>"<BR><FONT FACE="Courier New, monospace">%date% - + </FONT>current date, e. g. "<FONT FACE="Courier New, monospace">2010-07-13</FONT>"<BR><FONT FACE="Courier New, monospace">%week% - + </FONT>calendar week, e. g. "<FONT FACE="Courier New, monospace">28</FONT>"<BR><FONT FACE="Courier New, monospace">%month% - + </FONT>current month, e. g. "<FONT FACE="Courier New, monospace">July</FONT>"<BR><FONT FACE="Courier New, monospace">%year% - + </FONT>current year, e. g. "<FONT FACE="Courier New, monospace">2010</FONT>"</FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> diff --git a/BUILD/Help/html/advanced/CompareFileSize.html b/BUILD/Help/html/advanced/CompareFileSize.html index 54744b51..af184fd9 100644 --- a/BUILD/Help/html/advanced/CompareFileSize.html +++ b/BUILD/Help/html/advanced/CompareFileSize.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091209;21185800"> + <META NAME="CHANGED" CONTENT="20100902;19144900"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,27 +17,30 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> -<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Compare by -filesize</FONT></H3> +<BODY LANG="en-US" DIR="LTR"> +<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Compare by file +size</FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Sometimes -you might want to compare both sides by filesize only, ignoring last +you might want to compare both sides by file size only, ignoring last modification timestamps.</FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Instructions:</B></FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Open -your *.ffs_gui configuration file and change the value of XML node +file "</FONT><FONT FACE="Courier New, monospace">GlobalSettings.xml</FONT><FONT FACE="Tahoma, sans-serif">" +located either in "</FONT><FONT FACE="Courier New, monospace">%appdata%\FreeFileSync</FONT><FONT FACE="Tahoma, sans-serif">" +or the installation folder and change the value of XML node </FONT><FONT FACE="Courier New, monospace"><FileTimeTolerance></FONT> <FONT FACE="Tahoma, sans-serif">to some sufficiently large number of -seconds. Changed files will now be detected as a conflict (same date, -different filesize) and the default synchronization direction for -conflics can be used.</FONT></P> +seconds, for example 2.000.000.000. Changed files will now be +detected as a conflict (same date, different file size) and the +default synchronization direction for conflicts can be used.</FONT></P> </BODY> </HTML>
\ No newline at end of file diff --git a/BUILD/Help/html/advanced/DaylightSavingTime.html b/BUILD/Help/html/advanced/DaylightSavingTime.html index 4fffe036..b29a612a 100644 --- a/BUILD/Help/html/advanced/DaylightSavingTime.html +++ b/BUILD/Help/html/advanced/DaylightSavingTime.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091208;20054200"> - <META NAME="CHANGED" CONTENT="20091211;18381300"> + <META NAME="CHANGED" CONTENT="20100902;19275000"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,53 +17,50 @@ H2 { margin-bottom: 0.21cm } H2.western { font-family: "Arial", sans-serif; font-size: 14pt; font-style: italic } H2.cjk { font-family: "MS Mincho"; font-size: 14pt; font-style: italic } - H2.ctl { font-size: 14pt; font-style: italic } + H2.ctl { font-family: "Mangal"; font-size: 14pt; font-style: italic } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H2 CLASS="western" STYLE="font-style: normal"><FONT FACE="Tahoma, sans-serif">Daylight -saving time</FONT></H2> +saving time <SPAN STYLE="font-weight: normal">(Windows)</SPAN></FONT></H2> <P STYLE="margin-bottom: 0cm"><BR> </P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">A +common problem synchronization software has to deal with are +-1 hour +file time shifts after a Daylight Saving Time (DST) switch has +occurred. This can be observed for example when a FAT-formatted +volume is compared against an NTFS volume as frequently happening +with USB memory sticks. Files that previously appeared to be in sync +are now shown with an one hour modification time offset, although +they have not been modified by the user or by other means.</FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">The -Windows operating system exhibits quite a unique behavior when -handling timestamps on NTFS file systems. This leads to a well-known -issue that all file synchronization software has to handle:</FONT></P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">During -daylight saving time switching, (local) file times are shifted by one -hour on NTFS file systems, while NO shift occurs on FAT/FAT32 drives -(as used by most USB sticks)! Thus when synchronizing an NTFS against -a FAT32 volume file times become asynchronous twice a year!</FONT></P> +reason for this strange behavior lies in the way NTFS and FAT drives +store file times: NTFS stores time in UTC format, while FAT uses +local time.</FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">When +times stored in these two different formats are compared, one format +has to be converted into the other first. In both cases Windows uses +the current DST status as well as current time zone information for +its calculations. Consequently the result of this comparison is +dependent from current system settings and in particular file times +that used to be the same can show up as different after a DST switch.</FONT></P> +<P STYLE="margin-bottom: 0cm"><BR> +</P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">For a -comprehensive discussion about this issue refer -to:<BR><A HREF="http://www.codeproject.com/KB/datetime/dstbugs.aspx">http://www.codeproject.com/KB/datetime/dstbugs.aspx</A></FONT></P> +detailed discussion about this issue refer to: +<A HREF="http://www.codeproject.com/KB/datetime/dstbugs.aspx">http://www.codeproject.com/KB/datetime/dstbugs.aspx</A></FONT></P> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Solution:</B></FONT></P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">In -order to avoid re-copying files that have a modification time -difference of +-1h FreeFileSync offers a global option: <I>Menu -> -Advanced -> Global settings: Ignore 1-hour file time difference</I>.</FONT></P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">If -"<I>Ignore 1-hour file time difference</I>" is checked, all -files with a +-1h difference are treated as having the same time. -This also handles different file time precisions (NTFS: 100ns, -FAT/FAT32: 2 seconds) by allowing a 2 second tolerance .</FONT></P> -<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Files -that have a deviation of less than one hour are categorized as -conflicts. The reasoning is that these files surely have been -modified on at least one side since last synchronization. But during -one of the two daylight saving time switches per year the older file -is shown pretending a newer date which can lead to data loss (when -using the rule to overwrite older with newer files).</FONT></P> -<P STYLE="margin-left: 1.46cm; margin-bottom: 0cm"><SPAN ID="Rahmen1" 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>If synchronization - takes place between NTFS ↔ NTFS or FAT32 ↔ FAT32 this - checkbox provides no advantage and can be left unchecked.</FONT></P> -</SPAN><BR CLEAR=LEFT><BR> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Luckily +FreeFileSync users need not to worry about this issue. Each file on a +FAT volume automatically gets additional meta data encoded in its +creation date that enables a correct file time calculation. This not +only solves all DST issues but also time shifts that occur due to +travel between different time zones.</FONT></P> +<P STYLE="margin-bottom: 0cm"><BR> </P> </BODY> </HTML>
\ No newline at end of file diff --git a/BUILD/Help/html/advanced/EnvironmentVariables.html b/BUILD/Help/html/advanced/EnvironmentVariables.html index a85be8fd..26cffd7f 100644 --- a/BUILD/Help/html/advanced/EnvironmentVariables.html +++ b/BUILD/Help/html/advanced/EnvironmentVariables.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100218;65300"> + <META NAME="CHANGED" CONTENT="20100825;18572300"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,6 +17,7 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> @@ -29,9 +30,9 @@ Variables</FONT></H3> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">All directory names may contain macros that are expanded during synchronization. Begin and end of each macro is marked by a '%' -character. Besides special macros handling time and date (see -"Time-stamped directories"), the operating system's -environment variables can also be used.</FONT></P> +character. Besides special macros handling time and date (see "Backup +Strategies"), the operating system's 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><SPAN ID="Rahmen1" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> diff --git a/BUILD/Help/html/advanced/ExternalApp.html b/BUILD/Help/html/advanced/ExternalApp.html index 3994c96e..1c28932c 100644 --- a/BUILD/Help/html/advanced/ExternalApp.html +++ b/BUILD/Help/html/advanced/ExternalApp.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091212;16500300"> + <META NAME="CHANGED" CONTENT="20100902;19180200"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,18 +17,19 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Start an external application via double-click</FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">FreeFileSync opens the operating system's standard file browser per default on -each double-click e.g. by invoking "<FONT FACE="Courier New, monospace">explorer +each double-click e. g. by invoking "<FONT FACE="Courier New, monospace">explorer /select, %name</FONT>" on Windows.</FONT></P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">If some other application shall be started instead, just navigate to "</FONT><FONT FACE="Tahoma, sans-serif"><I>Menu diff --git a/BUILD/Help/html/advanced/Ftp.html b/BUILD/Help/html/advanced/Ftp.html index b55301be..028ca05d 100644 --- a/BUILD/Help/html/advanced/Ftp.html +++ b/BUILD/Help/html/advanced/Ftp.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20091209;21053000"> + <META NAME="CHANGED" CONTENT="20100902;19174600"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,22 +17,25 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Synchronize with -FTP</FONT></H3> +FTP/WebDAV <SPAN STYLE="font-weight: normal">(Windows)</SPAN></FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">FreeFileSync -does not support FTP directly. But the FTP functionality can be -easily integrated by mapping the FTP webspace to a drive letter:</FONT></P> +does not support accessing FTP volumes directly. But this +functionality can be integrated by mapping the FTP web space to a +drive letter:</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"> -Use the free utility NetDrive (<A HREF="http://www.netdrive.net/">http://www.netdrive.net</A>)</FONT></P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><B>Example:</B></FONT> +<FONT FACE="Tahoma, sans-serif">Use the free utility NetDrive +(<A HREF="http://www.netdrive.net/">http://www.netdrive.net</A>)</FONT></P> <UL> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Add a "<I>New Site</I>" and specify site name, site URL, drive @@ -43,10 +46,37 @@ Use the free utility NetDrive (<A HREF="http://www.netdrive.net/">http://www.net <P STYLE="margin-left: 1.46cm; margin-bottom: 0cm"><SPAN ID="Rahmen1" 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>Most FTP drives set - a file's timestamp to the current time when synchronizing ignoring + a file's time stamp to the current time when synchronizing ignoring the source file's time and date. As a workaround you can do a "<I>compare by filesize</I>"; see corresponding section.</FONT></P> </SPAN><BR CLEAR=LEFT><BR> </P> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Synchronize with +SFTP <SPAN STYLE="font-weight: normal">(Linux)</SPAN></FONT></H3> +<P STYLE="margin-bottom: 0cm"><BR> +</P> +<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">An SFTP +share can be easily mapped onto a local folder for use with +FreeFileSync:</FONT></P> +<UL> + <P><SPAN ID="Rahmen2" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> + <UL> + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Install:</FONT><FONT FACE="Courier New, monospace"><BR>sudo + apt-get install sshfs</FONT></P> + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Mount + SFTP share:</FONT><FONT FACE="Courier New, monospace"><BR>sshfs + ssh-account@ssh-server:[path] mountpoint</FONT></P> + <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Unmount:</FONT><FONT FACE="Courier New, monospace"><BR>fusermount + -u mountpoint</FONT></P> + </UL> + </SPAN><BR CLEAR=LEFT> + </P> +</UL> +<P><BR><BR> +</P> </BODY> </HTML>
\ No newline at end of file diff --git a/BUILD/Help/html/advanced/RealtimeSync.html b/BUILD/Help/html/advanced/RealtimeSync.html index 5aabe112..692a1b36 100644 --- a/BUILD/Help/html/advanced/RealtimeSync.html +++ b/BUILD/Help/html/advanced/RealtimeSync.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100428;21351600"> + <META NAME="CHANGED" CONTENT="20100902;19164200"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,6 +17,7 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> @@ -30,8 +31,8 @@ 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 within these directories or subdirectories is -modified OR the directory becomes available (e.g. insert of a +Whenever a file within these directories or sub directories 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> @@ -70,7 +71,7 @@ to begin monitoring.</FONT></P> OR a FreeFileSync Batch file (<FONT FACE="Courier New, monospace">*.ffs_batch</FONT>) as first command-line argument. Latter is implicitly converted to a *.ffs_real file with default settings. This allows for - integration with your operating system's autostart facility:</FONT></P> + integration with your operating system's auto start facility:</FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> @@ -112,7 +113,7 @@ analog to the following:</FONT></P> </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 +becomes available, the command-line executes and starts the batch job 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> diff --git a/BUILD/Help/html/advanced/RunAsService.html b/BUILD/Help/html/advanced/RunAsService.html index 499d0d4d..07bbb56d 100644 --- a/BUILD/Help/html/advanced/RunAsService.html +++ b/BUILD/Help/html/advanced/RunAsService.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100420;20042700"> + <META NAME="CHANGED" CONTENT="20100902;19154500"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,6 +17,7 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> @@ -90,7 +91,7 @@ it!</FONT></P> <P ALIGN=LEFT STYLE="margin-right: 0.98cm; margin-bottom: 0cm"><BR> </P> <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">The new -service can now be started via commandline or Windows Service +service can now be started via command line or Windows Service administration:</FONT></P> <UL> <P STYLE="margin-right: 0.98cm"><SPAN ID="Rahmen5" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> @@ -105,7 +106,7 @@ administration:</FONT></P> <P STYLE="margin-left: 1.46cm; margin-bottom: 0cm"><SPAN ID="Rahmen7" 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>By default the - service is created with startup type "automatic" which + service is created with start-up type "automatic" which runs it on Windows start. This behavior can be changed in Windows Service administration.</FONT></P> </SPAN><BR CLEAR=LEFT><BR> diff --git a/BUILD/Help/html/advanced/SendMail.html b/BUILD/Help/html/advanced/SendMail.html index d8fc7e9d..a3263f3c 100644 --- a/BUILD/Help/html/advanced/SendMail.html +++ b/BUILD/Help/html/advanced/SendMail.html @@ -5,7 +5,7 @@ <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100228;21172600"> + <META NAME="CHANGED" CONTENT="20100902;19140400"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,25 +17,24 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Synchronize in Batch Mode and send error notification via email</FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> </P> <OL> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create - a FreeFileSync batch file using "<I>Si</I><I>lent mode</I>".</FONT></P> - <P STYLE="margin-bottom: 0cm"></P> + a FreeFileSync batch file using "<I>Silent mode</I>".</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Set - error handling to "<I>Exit instantly</I>" or "<I>Ig</I><I>nore - errors</I>" to avoid having a popup stop the program flow. In - case errors occur FreeFileSync will exit with a returncode < 0 + error handling to "<I>Exit instantly</I>" or "<I>Ignore + errors</I>" to avoid having a pop-up stop the program flow. In + case errors occur FreeFileSync will exit with a return code < 0 that can be checked via the ERRORLEVEL batch command.</FONT></P> - <P STYLE="margin-bottom: 0cm"></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Create a *.cmd or *.bat file to specify the location of FreeFileSync.exe and pass the name of the FreeFileSync batch file as first argument; diff --git a/BUILD/Help/html/advanced/ShadowCopy.html b/BUILD/Help/html/advanced/ShadowCopy.html index d726ad76..98d50659 100644 --- a/BUILD/Help/html/advanced/ShadowCopy.html +++ b/BUILD/Help/html/advanced/ShadowCopy.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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100413;18262600"> + <META NAME="CHANGED" CONTENT="20100902;19132400"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -17,11 +17,12 @@ H3 { margin-bottom: 0.21cm } H3.western { font-family: "Arial", sans-serif } H3.cjk { font-family: "MS Mincho" } + H3.ctl { font-family: "Mangal" } A:link { so-language: zxx } --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Volume Shadow Copy Service <SPAN STYLE="font-weight: normal">(Windows only)</SPAN></FONT></H3> <P STYLE="margin-bottom: 0cm"><BR> @@ -38,12 +39,11 @@ Copy of the source drive. To enable this feature go to </FONT><FONT FACE="Tahoma <LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">This functionality is applied to locked files only. Regular files will not use Volume Shadow Copy Service when being synchronized.</FONT></P> - <P ALIGN=LEFT STYLE="margin-bottom: 0cm"></P> </UL> <UL> - <LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif"><SPAN STYLE="font-style: normal">Creating + <LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-style: normal"><FONT FACE="Tahoma, sans-serif">Creating Volume Snapshots using VSS requires the application to be started - with Administrator rights.</SPAN></FONT></P> + with Administrator rights.</FONT></P> </UL> </SPAN><BR CLEAR=LEFT> </P> @@ -56,7 +56,7 @@ Copy of the source drive. To enable this feature go to </FONT><FONT FACE="Tahoma <P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">If you experience problems using the Volume Shadow Copy Service a renewal of registration might help. Create and execute a *.cmd batch file with -the follow content or enter directly via commandline:</FONT></P> +the follow content or enter directly via command line:</FONT></P> <UL> <P STYLE="margin-right: 0.98cm"><SPAN ID="Rahmen3" DIR="LTR" STYLE="float: left; width: 80%; height: 0.14cm; border: none; padding: 0cm; background: #e6e6e6"> <P ALIGN=LEFT STYLE="margin-left: 0.79cm; margin-right: 0.98cm; margin-bottom: 0cm"> diff --git a/BUILD/Help/html/advanced/SymbolicLinks.html b/BUILD/Help/html/advanced/SymbolicLinks.html index 8117ab60..6efe1eb9 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.2 (Win32)"> <META NAME="CREATED" CONTENT="20091206;16574000"> - <META NAME="CHANGED" CONTENT="20100611;22010200"> + <META NAME="CHANGED" CONTENT="20100902;19130700"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -22,7 +22,7 @@ --> </STYLE> </HEAD> -<BODY LANG="de-DE" DIR="LTR"> +<BODY LANG="en-US" DIR="LTR"> <H3 CLASS="western"><FONT FACE="Tahoma, sans-serif">Symbolic link handling <SPAN STYLE="font-weight: normal">(Windows since Vista and Linux)</SPAN></FONT></H3> @@ -39,7 +39,7 @@ Links (also called Symlinks or Soft Links):</FONT></P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">"Direct" configures synchronization of the Symbolic Link object itself and not its target. Symbolic Links will be visible on main grid as a - separate entity with corresponding metadata. Links pointing to + separate entity with corresponding meta data. Links pointing to directories are not traversed and the Link object is copied directly during synchronization. <BR></FONT> </P> <LI><P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">"<I>Follow</I>" diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng index 6d621a2f..c5645a85 100644 --- a/BUILD/Languages/chinese_simple.lng +++ b/BUILD/Languages/chinese_simple.lng @@ -15,7 +15,7 @@ %x day(s) %x 天 %x directories -%x 目录 +%x 个目录 %x files %x 个文件 %x hour(s) @@ -27,7 +27,7 @@ %x of %y rows in view %y è¡Œä¸çš„ %x è¡Œå¯è§ %x of 1 row in view -%x of 1 è¡Œå¯è§ +1 è¡Œä¸çš„ %x è¡Œå¯è§ %x sec %x 秒 %x% @@ -90,8 +90,6 @@ 是(&Y) (Build: %x) (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ 通过å·å½±å¤åˆ¶æœåŠ¡å¤åˆ¶å…±äº«æˆ–é”定的文件\n(需è¦ç®¡ç†å‘˜æƒé™) Copy to clipboard\tCTRL+C å¤åˆ¶åˆ°å‰ªè´´æ¿\tCTRL+C -Copying Symbolic Link %x overwriting %y -æ£åœ¨å¤åˆ¶ç¬¦å·è¿žæŽ¥ %x 覆盖 %y -Copying Symbolic Link %x to %y -æ£åœ¨å¤åˆ¶ç¬¦å·è¿žæŽ¥ %x 到 %y -Copying file %x overwriting %y -æ£åœ¨å¤åˆ¶æ–‡ä»¶ %x 覆盖 %y -Copying file %x to %y -æ£å¤åˆ¶æ–‡ä»¶ %x 到 %y +Copying new Symbolic Link %x to %y +å¤åˆ¶æ–°ç¬¦å·è¿žæŽ¥ %x 到 %y +Copying new file %x to %y +å¤åˆ¶æ–°æ–‡ä»¶ %x 到 %y Could not determine volume name for file: ä¸èƒ½ç¡®å®šæ¤æ–‡ä»¶çš„å·å称: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! æ•°æ®æ ¡éªŒé”™è¯¯:æºæ–‡ä»¶å’Œç›®æ ‡æ–‡ä»¶å†…容ä¸åŒ! Date 日期 -Delay -延时 -Delay between detection of changes and execution of command line in seconds -在检测和执行命令行之间的延时秒数 Delete files/folders existing on left side only åˆ é™¤ä»…åœ¨å·¦ä¾§å˜åœ¨çš„文件/文件夹 Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: 从åŒæ¥æ•°æ®åº“ä¸è¯»å–时出错: Error resolving symbolic link: 解决符å·é“¾æŽ¥å‡ºé”™: +Error setting directory lock: +设置目录é”定时出错: Error setting privilege: 设置æƒé™æ—¶å‡ºé”™: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date 文件大å°å’Œæ—¥æœŸ Filename 文件å -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. -文件 %x 的时间差异å°äºŽ1å°æ—¶ï¼\n\n由于å¤ä»¤æ—¶çš„é—®é¢˜å› æ¤ä¸èƒ½å®‰å…¨åœ°åˆ¤æ–哪一个比较新. Files %x have the same date but a different size! 文件 %x 日期相åŒä½†å¤§å°ä¸åŒ! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage 主页 Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. 使用数æ®åº“æ¥è¯†åˆ«å’Œä¼ é€ä¸¤è¾¹çš„改å˜. è‡ªåŠ¨æ£€æµ‹åˆ é™¤å’Œå†²çªçŠ¶æ€. +Idle time between detection of last change and execution of command line in seconds +以秒计的最åŽå˜æ›´å’Œæ‰§è¡Œå‘½ä»¤è¡Œä¹‹é—´çš„空闲时间 If you like FFS å¦‚æžœä½ å–œæ¬¢ FFS Ignore 忽略 -Ignore 1-hour file time difference -忽略1å°æ—¶æ–‡ä»¶æ—¶é—´å·®å¼‚ Ignore errors 忽略错误 Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v ä¸æ”¯æŒåœ¨WOW64上使用å·å½±å¤åˆ¶. 请使用 FreeFileSync 64ä½ç‰ˆæœ¬. Match case 匹é…大å°å†™ +Minimum Idle Time +最å°ç©ºé—²æ—¶é—´ Mirror ->> é•œåƒ ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: æ“作: Overview æ‘˜è¦ +Overwriting Symbolic Link %x in %y +æ£åœ¨ %y 上覆盖符å·è¿žæŽ¥ %x +Overwriting file %x in %y +æ£åœ¨ %y 上覆盖文件 %x Pause æš‚åœ Paused @@ -793,7 +789,7 @@ Swap sides Switching to FreeFileSync GUI mode... 切æ¢è‡³FreeFileSync图形用户界é¢æ¨¡å—... Symbolic Link handling -æ£åœ¨å¤„ç†ç¬¦å·è¿žæŽ¥ +符å·è¿žæŽ¥å¤„ç†æ–¹å¼ Symlinks %x have the same date but a different target! 符å·è¿žæŽ¥ %x 有相åŒçš„æ—¥æœŸä½†ç›®æ ‡ä¸åŒ! Synchronization Preview @@ -842,8 +838,6 @@ Total time: 总共时间: Transfer file and directory permissions\n(Requires Administrator rights) 转移文件和目录的æƒé™\n(需è¦ç®¡ç†å‘˜æƒé™) -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 -对文件时间差异在精确的+/-1å°æ—¶çš„文件认为是相åŒçš„,å°äºŽ1å°æ—¶çš„认为是冲çªä»¥æ¤æ¥å¤„ç†å¤ä»¤æ—¶çš„å˜åŒ– Unable to connect to sourceforge.net! æ— æ³•é“¾æŽ¥åˆ° Sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! å·å %x 并éžæ–‡ä»¶å %y 的一部分! Waiting for all directories to become available... ç‰å¾…所有目录转为å¯ç”¨çŠ¶æ€... +Waiting while directory is locked (%x)... +由于目录已é”定而æ£åœ¨ç‰å¾…(%x)... Warning è¦å‘Š Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng index 57b5e5aa..6e36eb07 100644 --- a/BUILD/Languages/chinese_traditional.lng +++ b/BUILD/Languages/chinese_traditional.lng @@ -90,8 +90,6 @@ 是 (Build: %x) (建立:%x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ 複製共用或鎖定檔案使用使用å·å½±è¤‡è£½æœå‹™\n(需è¦ç®¡ç†å“¡æ¬Šé™) Copy to clipboard\tCTRL+C 複製到剪貼簿\tCTRL+C -Copying Symbolic Link %x overwriting %y -æ£åœ¨è¤‡è£½ç¬¦è™Ÿé€£çµ %x 覆蓋到 %y -Copying Symbolic Link %x to %y -æ£åœ¨è¤‡è£½ç¬¦è™Ÿé€£çµ %x 到 %y -Copying file %x overwriting %y -æ£åœ¨è¤‡è£½æª”案 %x 覆蓋到 %y -Copying file %x to %y -æ£åœ¨è¤‡è£½æª”案 %x 到 %y +Copying new Symbolic Link %x to %y + +Copying new file %x to %y + Could not determine volume name for file: 無法判斷æ¤æª”案的å·æ¨™å稱: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! 資料驗è‰éŒ¯èª¤ï¼šä¾†æºå’Œç›®çš„檔案內容ä¸åŒï¼ Date 日期 -Delay -å»¶é² -Delay between detection of changes and execution of command line in seconds -檢測更改和執行命令列的延é²æ™‚間,以秒為單ä½ã€‚ Delete files/folders existing on left side only 刪除åªå˜åœ¨æ–¼å·¦é‚Šçš„檔案/資料夾 Delete files/folders existing on right side only @@ -460,8 +450,6 @@ File size and date 檔案大å°å’Œæ—¥æœŸ Filename 檔案å稱 -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. -檔案 %x 有一個檔案時差在1å°æ™‚å…§ï¼\n\n這ä¸æ˜¯å®‰å…¨çš„決定,其ä¸ä¹‹ä¸€æ˜¯ç”±æ–¼æ–°çš„日光節約時間的å•é¡Œã€‚ Files %x have the same date but a different size! 檔案 %x 日期相åŒä½†å¤§å°ä¸åŒï¼ Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ Homepage 首é Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. å°å…©é‚Šä½¿ç”¨åŒä¸€å€‹è³‡æ–™åº«çš„è˜åˆ¥å’Œå‚³é€æ›´æ”¹ã€‚自動檢測刪除和è¡çªéƒ¨ä»½ã€‚ +Idle time between detection of last change and execution of command line in seconds + If you like FFS å¦‚æžœä½ å–œæ¡ FFS Ignore 忽略 -Ignore 1-hour file time difference -忽略1å°æ™‚的檔案時差 Ignore errors 忽略錯誤 Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v ä¸æ”¯æ´è£½ä½œ WOW64 上的å·å½±å‰¯æœ¬ã€‚請使用 FreeFileSync 64ä½å…ƒç‰ˆæœ¬ã€‚ Match case å€åˆ†å¤§å°å¯« +Minimum Idle Time + Mirror ->> é¡åƒ ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: æ“作: Overview æ‘˜è¦ +Overwriting Symbolic Link %x in %y + +Overwriting file %x in %y + Pause æš«åœ Paused @@ -702,8 +696,6 @@ Remove folder 移除資料夾 Remove folder pair 移除一å°è³‡æ–™å¤¾ -Removing abandoned directory lock (%x)... - Report translation error å›žå ±ç¿»è¯éŒ¯èª¤ Reset @@ -846,8 +838,6 @@ Total time: 全部時間: Transfer file and directory permissions\n(Requires Administrator rights) 傳輸檔案和目錄權é™\n(需è¦ç®¡ç†å“¡æ¬Šé™) -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 -å°æª”案時差在精確的+/-1å°æ™‚的檔案判斷視為相åŒçš„,以å°æ–¼1å°æ™‚作為è¡çªï¼Œæ˜¯ç‚ºäº†è™•ç†æ—¥å…‰ç¯€ç´„時間的變化 Unable to connect to sourceforge.net! 無法連接到 sourceforge.netï¼ Unable to create logfile! diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng index c7e486a5..976d32ce 100644 --- a/BUILD/Languages/czech.lng +++ b/BUILD/Languages/czech.lng @@ -90,8 +90,6 @@ U&konÄit &Ano (Build: %x) (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ KopÃrovat sdÃlené nebo zamÄené soubory pomocà Volume Shadow Copy Service\n(Vyžaduje administrátorské oprávnÄ›nÃ) Copy to clipboard\tCTRL+C Vložit do schránky\tCTRL+C -Copying Symbolic Link %x overwriting %y -KopÃrovánà symbolického odkazu %x pÅ™es %y -Copying Symbolic Link %x to %y +Copying new Symbolic Link %x to %y KopÃrovánà symbolického odkazu %x do %y -Copying file %x overwriting %y -KopÃrovánà soubor %x pÅ™es %y -Copying file %x to %y -KopÃrovánà souboru %x do %y +Copying new file %x to %y +KopÃrovánà nového souboru %x do %y Could not determine volume name for file: Nenà možné zjistit jméno jednotky souboru: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Chyba verifikace dat: Zdrojový a cÃlový soubor majà rozdÃlný obsah! Date Datum -Delay -ZpoždÄ›nà -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Ä› Delete files/folders existing on right side only @@ -370,6 +360,8 @@ Elements remaining: Zbývá položek: Email Email +Encode extended time information: %x + Endless loop when traversing directory: Zacyklenà pÅ™i procházenà adresáře: Error @@ -413,7 +405,7 @@ Chyba Ätenà synchronizaÄnà databáze: Error resolving symbolic link: Chyba odkazu zástupce: Error setting directory lock: - +Chyba nastavenà zámku adresáře: Error setting privilege: Chyba nastavenà práv: Error starting Volume Shadow Copy Service! @@ -460,8 +452,6 @@ File size and date Podle velikosti a data souboru Filename Jméno -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. -Soubory %x se liÅ¡Ã o ménÄ› než 1 hodinu.\n\nnenà možné bezpeÄnÄ› rozhodnout, který z nich je novÄ›jÅ¡Ã kvůli použÃvánà LetnÃho Äasu. Files %x have the same date but a different size! Soubory %x majà stejné datum a Äas ale rozdÃlnou velikost! Files are found equal if\n - file content\nis the same @@ -566,12 +556,12 @@ Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Rozpoznat a provést zmÄ›ny na obou stranách pomocà databáze. OdstranÄ›né soubory a konflikty budou detekovány automaticky. +Idle time between detection of last change and execution of command line in seconds +Prodleva mezi detekcà poslednà zmÄ›ny a spuÅ¡tÄ›nÃm pÅ™Ãkazu (v sekundách) If you like FFS Pokud se Vám FSS lÃbà Ignore PÅ™eskoÄit -Ignore 1-hour file time difference -Ignorovat 1 hodinu rozdÃlu v Äase mezi soubory Ignore errors Ignorovat chyby Ignore subsequent errors @@ -614,6 +604,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Vytvářenà stÃnových kopià na WOW64 nenà podporováno. ProsÃm použijte 64 bitovou verzi FreeFileSync. Match case RozliÅ¡ovat malá a velká pÃsmena +Minimum Idle Time +Minimálnà Äas prodlevy Mirror ->> Zrcadlenà ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +660,10 @@ Operation: Operace: Overview PÅ™ehled +Overwriting Symbolic Link %x in %y +PÅ™epis symbolického odkazu %x v %y +Overwriting file %x in %y +PÅ™epis souboru %x v %y Pause Pauza Paused @@ -702,8 +698,6 @@ Remove folder Odstranit adresář Remove folder pair Odstranit dvojici adresářů -Removing abandoned directory lock (%x)... - Report translation error Hlásit chyby pÅ™ekladu Reset @@ -810,8 +804,6 @@ Synchronization completed with errors! Synchronizace dokonÄena s chybami. Synchronization settings Nastavenà synchronizace -Synchronization status -Stav synchronizace Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". Synchronizovat vÅ¡echny soubory .doc, .zip a .exe s výjimkou vÅ¡eho v podadresáři \"temp\" Synchronize... @@ -846,8 +838,6 @@ Total time: Celkový Äas: Transfer file and directory permissions\n(Requires Administrator rights) PÅ™enést pÅ™Ãstupová oprávnÄ›nà souborů a adresářů\n(Vyžaduje administrátorké oprávnÄ›nÃ) -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 -Považovat Äas souboru liÅ¡Ãcà se pÅ™esnÄ› o +/- 1 hodinu jako shodný, ménÄ› než 1 hodinu jako konflikt, kvůli zpracovánà a pÅ™echodům na Letnà Äas Unable to connect to sourceforge.net! Nenà možné se pÅ™ipojit k sourceforge.net! Unable to create logfile! @@ -875,7 +865,7 @@ Disk %x nenà souÄástà jména souboru %y! Waiting for all directories to become available... ÄŒekánà na zpÅ™ÃstupnÄ›nà vÅ¡ech adresářů... Waiting while directory is locked (%x)... - +ÄŒekánà na uzamÄenà adresáře (%x) Warning Varovánà Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng index 054db99d..ee674596 100644 --- a/BUILD/Languages/dutch.lng +++ b/BUILD/Languages/dutch.lng @@ -90,8 +90,6 @@ &Ja (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copy to clipboard\tCTRL+C Kopieer naar het klembord\tCTRL+C -Copying Symbolic Link %x overwriting %y +Copying new Symbolic Link %x to %y -Copying Symbolic Link %x to %y +Copying new file %x to %y -Copying file %x overwriting %y - -Copying file %x to %y -Bestand %x wordt gekopieerd naar %y Could not determine volume name for file: Kon de schijfnaam niet vaststellen van bestand: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Dataverificatie-fout: Bron en doelbestand hebben verschillende inhoud! Date Datum -Delay -Vertraging -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 Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: Er is een fout opgetreden bij het lezen van de synchronisatie-database: Error resolving symbolic link: Er is een fout opgetreden bij het ophalen van een symbolische koppeling: +Error setting directory lock: + Error setting privilege: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date Bestandsgrootte en -datum Filename Bestandsnaam -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. -De bestanden %x hebben een bestandstijd verschil van minder dan één uur!\n\nHet is niet veilig te bepalen welke nieuwer is vanwege zomertijd instellingen Files %x have the same date but a different size! De bestanden %x hebben dezelfde data maar een afwijkende grootte! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identificeer en verwerk verandereringen aan beide kanten dmv een database. Verschillen en conflicten worden automatisch gedecteerd. +Idle time between detection of last change and execution of command line in seconds + If you like FFS Als het programma u bevalt Ignore -Ignore 1-hour file time difference -Negeer 1-uur bestandstijd verschillen Ignore errors Negeer foutmeldingen Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Schaduw kopieen op WOW64 worden niet ondersteund. Gebruik alstublieft de 64-bit versie van FreeFileSync. Match case +Minimum Idle Time + Mirror ->> Spiegelen ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Voortgang: Overview Overzicht +Overwriting Symbolic Link %x in %y + +Overwriting file %x in %y + Pause Pause Paused @@ -842,8 +838,6 @@ Total time: Totale tijd: Transfer file and directory permissions\n(Requires Administrator rights) -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 -Behandel bestandstijden die verschillen met precies +/- 1 uur als gelijk en minder als 1 uur als conflict om zomertijd veranderingen te verwerken Unable to connect to sourceforge.net! Niet in staat verbinding te maken met sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Volume naam %x maakt niet deel uit van bestandsnaam %y! Waiting for all directories to become available... +Waiting while directory is locked (%x)... + Warning Attentie Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/english_uk.lng b/BUILD/Languages/english_uk.lng index a020bd25..eab1c880 100644 --- a/BUILD/Languages/english_uk.lng +++ b/BUILD/Languages/english_uk.lng @@ -90,8 +90,6 @@ &Yes (Build: %x) (Build: %x) -(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 that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) (Requires an Internet connection!) (Requires an Internet connection!) - Other side's counterpart to %dir @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administrator rights) Copy to clipboard\tCTRL+C Copy to clipboard\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copying Symbolic Link %x overwriting %y -Copying Symbolic Link %x to %y -Copying Symbolic Link %x to %y -Copying file %x overwriting %y -Copying file %x overwriting %y -Copying file %x to %y -Copying file %x to %y +Copying new Symbolic Link %x to %y +Copying new Symbolic Link %x to %y +Copying new file %x to %y +Copying new file %x to %y Could not determine volume name for file: Could not determine volume name for file: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Data verification error: Source and target file have different content! Date Date -Delay -Delay -Delay between detection of changes and execution of command line in seconds -Delay between detection of changes and execution of command line in seconds Delete files/folders existing on left side only Delete files/folders existing on left side only Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: Error reading from synchronisation database: Error resolving symbolic link: Error resolving symbolic link: +Error setting directory lock: +Error setting directory lock: Error setting privilege: Error setting privilege: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date File size and date Filename Filename -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. -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. Files %x have the same date but a different size! Files %x have the same date but a different size! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. +Idle time between detection of last change and execution of command line in seconds +Idle time between detection of last change and execution of command line in seconds If you like FFS If you like FFS Ignore Ignore -Ignore 1-hour file time difference -Ignore 1-hour file time difference Ignore errors Ignore errors Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. Match case Match case +Minimum Idle Time +Minimum Idle Time Mirror ->> Mirror ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Operation: Overview Overview +Overwriting Symbolic Link %x in %y +Overwriting Symbolic Link %x in %y +Overwriting file %x in %y +Overwriting file %x in %y Pause Pause Paused @@ -842,8 +838,6 @@ Total time: Total time: Transfer file and directory permissions\n(Requires Administrator rights) Transfer file and directory permissions\n(Requires Administrator rights) -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 -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 Unable to connect to sourceforge.net! Unable to connect to sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Volume name %x not part of filename %y! Waiting for all directories to become available... Waiting for all directories to become available... +Waiting while directory is locked (%x)... +Waiting while directory is locked (%x)... Warning Warning Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng index 6ca7cda8..77c39c55 100644 --- a/BUILD/Languages/finnish.lng +++ b/BUILD/Languages/finnish.lng @@ -13,23 +13,23 @@ %x TB %x TB %x day(s) - +%x päiviä %x directories %x hakemistoa %x files %x tiedostoista %x hour(s) - +% tunteja %x kB %x kB %x min - +%x min %x of %y rows in view %x riviä %y rivistä näytössä %x of 1 row in view %x 1 rivistä näytössä %x sec - +%x s %x% %x% &Abort @@ -45,7 +45,7 @@ Etsi &uusi versio &Content &Sisältö &Create batch job... -&Tee eräajo... +&Luo eräajo... &Default &Vakio &Exit @@ -90,8 +90,6 @@ Asetusten &lataus... &Kyllä (Build: %x) (Versio: %x) -(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!) (Vaatii Internet-yhteyden!) - Other side's counterpart to %dir @@ -179,13 +177,13 @@ Tiedoston on avattu seuraaviin luokkiin: 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: 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. +Luo komentotiedosto täsmäytyksen automaattiseen eräajoon. Käynnistä eräajo liittämällä FreeFileSync 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. Vähintäin yksi hakemiston syöttökenttä on tyhjä. Auto-adjust columns Säädä sarakeleveys automaattisesti Batch execution -Eräajo +Eräajon suoritus Batch file created successfully! Eräajotiedosto luotu onnistuneesti! Batch job @@ -257,7 +255,7 @@ Jatka Conversion error: Konversio virhe: Copy filesystem permissions - +Monista tiedosto-oikeudet Copy from left to right Kopioidaan vasen -> oikea Copy from left to right overwriting @@ -271,17 +269,13 @@ Kopioi lukitut tiedostot 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\n(Requires Administrator rights) - +Kopioi jaetut/lukitut tiedostot Volume Shadow Copy prosessilla\n(Vaatii Järjestelmävalvojan oikeuksia) Copy to clipboard\tCTRL+C Kopioi Leikepöydälle\tCTRL+C -Copying Symbolic Link %x overwriting %y -Kopioin Symlinkki %x ylikirjoittamalla %y -Copying Symbolic Link %x to %y -Kopioin Symlinkki %x -> %y -Copying file %x overwriting %y -Kopioin tiedostoa %x ylikirjoittaen %y -Copying file %x to %y -Kopioin tiedostoa %x -> %y +Copying new Symbolic Link %x to %y +Kopioi uusi Symlinkki %x -> %y +Copying new file %x to %y +Kopioi uusi tiedosto %x -> %y Could not determine volume name for file: Levyasemaa ei tunnistettu tiedostolle: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Tiedon varmennusvirhe: Lähteellä ja kohteella on eri sisältö! Date Päiväys -Delay -Viive -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 Delete files/folders existing on right side only @@ -377,7 +367,7 @@ Virhe Error changing modification time: Virhe muuttaessa tiedoston aikaa: Error copying file permissions: - +Virhe kopioitaessa tiedoston oikeuksia: Error copying file: Virhe kopioitaessa tiedostoa: Error copying locked file %x! @@ -412,8 +402,10 @@ Error reading from synchronization database: Virhe lukiessa täsmäytyksen tietokantaa: Error resolving symbolic link: Virhe selvittäessä symbolista linkkiä: +Error setting directory lock: +Virhe asettaessa hakemiston lukkoa: Error setting privilege: - +Virte oikeuksia asettaessa: Error starting Volume Shadow Copy Service! Virhe käynnistäessä Volume Shadow Copy Service! Error traversing directory: @@ -458,8 +450,6 @@ File size and date Tiedoston koko ja päiväys Filename Tiedostonimi -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. -Tiedostojen %x aikaleima poikkeaa alle tunnin!\n\nEi voida päättää turvallisesti, kesäajan takia, kumpi on uudempi. Files %x have the same date but a different size! Tiedostot %x samalta päivältä mutta koko poikkeaa! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Kotisivu Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Tunnista ja monista muutokset molemmilla puolilla tietokannalla. Poistot ja ristiriidat hoidetaan automaattisesti. +Idle time between detection of last change and execution of command line in seconds +Joutoaika viimeisen muutos havainnon ja käskyn suorittamisen välillä, sekunneissa If you like FFS Jos pidät FFS:tä Ignore Sivuta -Ignore 1-hour file time difference -Älä huomioi 1. tunnin poikkeamaa Ignore errors Älä huomioi virheitä Ignore subsequent errors @@ -593,7 +583,7 @@ Ensi täsmäytys: Integrate external applications into context menu. The following macros are available: Liitä ulkoinen sovellus viitekehysvalikkoon. Seuraavat makrot ovat valittavissa: Invalid FreeFileSync config file! - +Virheellinen FreeFileSync asetustiedosto! Leave as unresolved conflict Jätä ratkaisemattomana virheenä Left @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v WOW64 varjokopiointia ei tueta. Käytä FreeFileSync 64-bittistä versiota. Match case Täsmää kirjainkoko +Minimum Idle Time +Min. joutoaika Mirror ->> Peilaava ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Toiminto: Overview Yleiskatsaus +Overwriting Symbolic Link %x in %y +Ylikirjoita Symlinkki %x kohdassa %y +Overwriting file %x in %y +Ylikirjoita tiedosto %x kohdassa %y Pause Tauko Paused @@ -827,7 +823,7 @@ Asetustiedosto ei ole kelvollinen: The file was not processed by last synchronization! Tiedostoa ei käsitelty viime täsmäytyksessä! 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. -Tämä vaihtoehto todennetaan kaksi samannimistä tiedostoa samaksi, jos koko JA viimeinen tallennusaika on sama. +Tämä vaihtoehto todentaan kaksi samannimistä tiedostoa samaksi, jos koko JA viimeinen tallennusaika on sama. Time Aika Time elapsed: @@ -841,9 +837,7 @@ Vaadittu vapaa levytila: Total time: Kokonaisaika: Transfer file and directory permissions\n(Requires Administrator rights) - -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 -Kohtele tiedostoja jolla aikaleima on tasan +/- tunti samoina, korjaa kesäajan siirtoa +Siirrä tiedosto ja hekimisto-oikeuksia\n(Vaatii Järjestelmävalvojan oikeuksia) Unable to connect to sourceforge.net! Kytkeytyminen ei onnistu kohteeseen sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Osan nimi %x ei esiinny tiedostonimessä %y! Waiting for all directories to become available... Odotan että kaikki hakemistot ovat saatavilla ... +Waiting while directory is locked (%x)... +Odotan hakemiston lukitusta (%x)... Warning Varoitus Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng index 51e2adaa..9d47b8e7 100644 --- a/BUILD/Languages/french.lng +++ b/BUILD/Languages/french.lng @@ -90,8 +90,6 @@ &Oui (Build: %x) (Généré : %x) -(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 concernés par ce problème !\nDans tous 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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ La copie des fichiers partagés ou verrouillés nécessite le Service Volume Shadow Copy\n(avec les droits administrateur) Copy to clipboard\tCTRL+C Copier dans le presse-papiers\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copie du Lien Symbolique %x remplaçant %y -Copying Symbolic Link %x to %y -Copie du Lien Symbolique %x vers %y -Copying file %x overwriting %y -Copie du fichier %x remplaçant %y -Copying file %x to %y -Copie le fichier %x vers %y +Copying new Symbolic Link %x to %y +Copie le nouveau Lien Symbolique %x vers %y +Copying new file %x to %y +Copie le nouveau fichier %x vers %y Could not determine volume name for file: Impossible de trouver le nom de volume pour le fichier : Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Erreur lors du contrôle des données : Les fichiers source et destination ont des contenus différents ! Date Date -Delay -Délai -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/dossiers n'existant que sur le côté gauche Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: Erreur lors de la lecture de la base de données de synchro : Error resolving symbolic link: Erreur lors de la résolution du lien symbolique : +Error setting directory lock: +Erreur lors du verrouillage du répertoire : Error setting privilege: Erreur de paramétrage de privilège Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date Taille et date du fichier Filename Nom du fichier -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. -Les fichiers %x ont une différence de date inférieure à 1 heure !\n\nIl est dangereux de décider quel est le plus récent à cause de l'heure d'été. Files %x have the same date but a different size! Les fichiers %x ont la même date mais une taille différente ! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Accueil Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identifier et propager les modifications des deux côtés en utilisant une base de données. Les suppressions et les conflits sont détectés automatiquement. +Idle time between detection of last change and execution of command line in seconds +Temps mort entre la détection de la dernière modification et l'éxécution de la ligne de commande en secondes If you like FFS Si vous aimez FFS Ignore Ignorer -Ignore 1-hour file time difference -Ignorer les diférences d'une heure Ignore errors Ignorer les erreurs Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v La copie en tâche de fond sur WOW64 n'est pas possible. Utilisez pour cela la version 64 bits de FreeFileSync. Match case Respecter la casse +Minimum Idle Time +Temps mort minimum Mirror ->> Miroir ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Opération : Overview Présentation +Overwriting Symbolic Link %x in %y +Remplacement du Lien Symbolique %x par %y +Overwriting file %x in %y +Remplacement du fichier %x par %y Pause Pause Paused @@ -842,8 +838,6 @@ Total time: Durée totale : Transfer file and directory permissions\n(Requires Administrator rights) Transfert des attributs système des fichiers et des répertoires\n(avec les droits administrateur) -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 -Traiter les heures qui diffèrent exactement de +/- 1 heure comme égales, et celles qui diffèrent de moins d'une heure comme conflit sur la gestion de l'heure d'été Unable to connect to sourceforge.net! Impossible de se connecter à sourceforge.net ! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Le nom de volume %x ne fait pas partie du nom de fichier %y ! Waiting for all directories to become available... En attente de la disponibilité de tous les répertoires... +Waiting while directory is locked (%x)... +En attente tant que le répertoire est verrouillé (%x)... Warning Attention Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng index c7a23e4a..105b302e 100644 --- a/BUILD/Languages/german.lng +++ b/BUILD/Languages/german.lng @@ -90,8 +90,6 @@ Konfiguration &laden... &Ja (Build: %x) (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Kopiere gesperrte Dateien mit Hilfe des Volume Shadow Copy Service\n(Benötigt Administratorrechte) Copy to clipboard\tCTRL+C In die Zwischenablage kopieren\tCTRL+C -Copying Symbolic Link %x overwriting %y -Kopiere Symbolischen Link %x und überschreibe %y -Copying Symbolic Link %x to %y -Kopiere Symbolischen Link %x nach %y -Copying file %x overwriting %y -Kopiere Datei %x und überschreibe %y -Copying file %x to %y -Kopiere Datei %x nach %y +Copying new Symbolic Link %x to %y +Kopiere neuen Symbolischen Link %x nach %y +Copying new file %x to %y +Kopiere neue Datei %x nach %y Could not determine volume name for file: Der Laufwerksname für folgende Datei konnte nicht ermittelt werden: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Verifizierungsfehler: Quell- und Zieldatei haben unterschiedlichen Inhalt! Date Datum -Delay -Verzögerung -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 Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: Fehler beim Lesen der Synchronisationsdatenbank: Error resolving symbolic link: Fehler beim Auflösen des Symbolischen Links: +Error setting directory lock: +Fehler beim Setzen der Verzeichnissperre: Error setting privilege: Fehler beim Setzen des Privilegs: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date Dateigröße und -datum Filename Dateiname -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. -Die Dateien %x haben eine Abweichung der Dateizeit von unter einer Stunde!\n\nAufgrund der Zeitumstellungsproblematik kann nicht zweifelsfrei festgestellt werden, welche die aktuellere ist. Files %x have the same date but a different size! Die Dateien %x haben dasselbe Datum, aber eine unterschiedliche Größe! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identifiziere und propagiere Änderungen auf beiden Seiten mit Hilfe einer Datenbank. Löschungen und Konflikte werden automatisch erkannt. +Idle time between detection of last change and execution of command line in seconds +Ruhezeit zwischen Erkennung der letzten Änderung und Aufrufen der Kommandozeile in Sekunden If you like FFS FFS unterstützen Ignore Ignorieren -Ignore 1-hour file time difference -Zeitunterschied von einer Stunde ignorieren Ignore errors Fehler ignorieren Ignore subsequent errors @@ -605,13 +595,15 @@ Konfiguration aus Datei laden Load configuration history (press DEL to delete items) Lade Konfigurationshistorie (DEL-Taste löscht Einträge) Log-messages: -Protokollmeldungen: +Meldungen: 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. Match case Groß-/Kleinschreibung +Minimum Idle Time +Minimale Ruhezeit Mirror ->> Spiegeln ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Vorgang: Overview Ãœbersicht +Overwriting Symbolic Link %x in %y +Ãœberschreibe Symbolischen Link %x in %y +Overwriting file %x in %y +Ãœberschreibe Datei %x in %y Pause Pause Paused @@ -842,8 +838,6 @@ Total time: Gesamtzeit: Transfer file and directory permissions\n(Requires Administrator rights) Ãœbertrage Datei- und Verzeichnisberechtigungen\n(Benötigt Administratorrechte) -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 -Betrachte Dateizeiten mit einer Differenz von genau +/- einer Stunde als gleich, mit weniger als einer Stunde als Konflikt, um Zeitumstellungen richtig zu behandeln Unable to connect to sourceforge.net! Es konnte keine Verbindung zu sourceforge.net aufgebaut werden! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Laufwerksname %x ist kein Teil des Dateinamens %y! Waiting for all directories to become available... Warte, bis alle Verzeichnisse verfügbar sind... +Waiting while directory is locked (%x)... +Warte während Verzeichnis gesperrt ist (%x)... Warning Warnung Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/hebrew.lng b/BUILD/Languages/hebrew.lng index 69b53a86..3c487fc7 100644 --- a/BUILD/Languages/hebrew.lng +++ b/BUILD/Languages/hebrew.lng @@ -90,8 +90,6 @@ &כן (Build: %x) -(Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".) -(×©×™× ×œ×‘: רק ×›×•× × ×™× ×§×©×™×—×™× ×ž×¡×•×’ פ×ט-פ×ט32 ×ž×•×©×¤×¢×•× ×ž×‘×¢×™×” ×–×ת \מ ) (Requires an Internet connection!) (מחייב קישור ××™× ×˜×¨× ×˜×™ פעיל!) - Other side's counterpart to %dir @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copy to clipboard\tCTRL+C העתק למכתבה \tCTRL+C -Copying Symbolic Link %x overwriting %y +Copying new Symbolic Link %x to %y -Copying Symbolic Link %x to %y +Copying new file %x to %y -Copying file %x overwriting %y - -Copying file %x to %y -העתק קובץ %x nach %y Could not determine volume name for file: ×œ× ×™×›×•×œ לקבוע ×©× ×›×•× ×Ÿ לקובץ: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! !טעות של ×ימות × ×ª×•× ×™× ×§×•×‘×¥ מקור ומטרה בעלי תכולת × ×ª×•× ×™× ×©×•× ×” Date ת×רין -Delay -השהייה -Delay between detection of changes and execution of command line in seconds -השהייה בין גילוי של ×©×™× ×•×™ לבין הפעלה של שורת פקודות ×‘×©× ×™×•×ª Delete files/folders existing on left side only מחק ×§×‘×¦×™× -תיקיות ×”×§×™×ž×™× ×ך ורק בצד שמ×ל Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: טעות בקרי××” מבסיס ×”× ×ª×•× ×™× ×©×œ ×”×¡× ×›×¨×•×Ÿ: Error resolving symbolic link: טעות ×‘×¤×¢× ×•×— מר××” ×ž×§×•× ×¡×™×ž×œ×™ (Symbolic Link) +Error setting directory lock: + Error setting privilege: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date גודל קובץ ות×ריך Filename ×©× ×§×•×‘×¥ -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. -קובץ %x × ×©×ž×¨ בשעה הבדל!\n\n ×ין ×פשרות להחליט מי ×ž×”×§×‘×¦×™× ×—×“×© יותר בגלל ×פשרות שעון קייץ Files %x have the same date but a different size! קובץ %x בעל ת×ריך ×–×”×” ×ך גודל ×©×•× ×” Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage :×תר-הבית Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. ×–×”×” והפץ ×©×™× ×•×™×™× ×‘×©× ×™×™ ×”×¦×“×“×™× ×‘×¢×–×¨×ª בסיס × ×ª×•× ×™× ×ž×—×™×§×•×ª ×•×§×•× ×¤×œ×™×§×˜×™× ×ž×–×•×”×™× ×‘×ופן ×וטומטי +Idle time between detection of last change and execution of command line in seconds + If you like FFS :תרומה תתקבל בברכה Ignore -Ignore 1-hour file time difference -×”×ª×¢×œ× ×ž-1 שעה הבדל בזמן השמירה של הקובץ -בעית שעון קיץ Ignore errors ×”×ª×¢×œ× ×ž×˜×¢×•×™×•×ª Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v ×œ× × ×ª×ž×›×ª בגרסה ×–×ת ×× × ×”×ª×§×Ÿ גרסה 64 WOW64 העתקת צל ב Match case ×ותיות הת×× +Minimum Idle Time + Mirror ->> מר××” ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: פעולה: Overview מבט כללי +Overwriting Symbolic Link %x in %y + +Overwriting file %x in %y + Pause עצור Paused @@ -842,8 +838,6 @@ Total time: זמן מקומי: Transfer file and directory permissions\n(Requires Administrator rights) -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 -התיחס ×œ×–×ž× ×™ הקובץ ×›×שר ×”× ×©×•× ×™× ×‘×“×™×•×§ ב +/- שעה ×›×©×•×•×™× ×œ×¦×•×¨×š פתרון בעית שעון קיץ Unable to connect to sourceforge.net! ×ין תקשורת ל sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! ×›× ×•× ×Ÿ %x ×œ× ×‘× ×ª×™×‘ של קובץ %y! Waiting for all directories to become available... מחכה ×œ×”×ª×¤× ×•×ª כל המחיצות... +Waiting while directory is locked (%x)... + Warning ×זהרה Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/hungarian.lng b/BUILD/Languages/hungarian.lng index 51f228f3..79cbd932 100644 --- a/BUILD/Languages/hungarian.lng +++ b/BUILD/Languages/hungarian.lng @@ -90,8 +90,6 @@ &Igen (Build: %x) (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ A megosztott vagy zárolt fájlok másolása a Volume Shadow Copy szolgáltatással\n(Adminisztrátori jogok szükségesek) Copy to clipboard\tCTRL+C Másolás a vágólapra\tCTRL+C -Copying Symbolic Link %x overwriting %y -A(z) %x symlink másolása fölülÃrva a következÅ‘t: %y -Copying Symbolic Link %x to %y -A(z) %x symlink másolása ide: %y -Copying file %x overwriting %y -A(z) %x fájl másolása fölülÃrva a következÅ‘t: %y -Copying file %x to %y -%x fájl másolása a(z) %y fájlba +Copying new Symbolic Link %x to %y + +Copying new file %x to %y + 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: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! AdatellenÅ‘rzési hiba: A forrás és cél fájl tartalma különbözik! Date Dátum -Delay -Várakozás -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 Delete files/folders existing on right side only @@ -460,8 +450,6 @@ File size and date fájlméret és dátum alapján Filename Fájlnév -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. -A(z) %x fájlok dátuma kevesebb mint 1 órával eltér!\n\nA nyári idÅ‘számÃtás miatt nem biztonságos annak eldöntése, hogy melyik az újabb közülük. Files %x have the same date but a different size! A(z) %x fájlok dátuma megegyezik, de a mérete nem! Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ Homepage Honlap Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Mindkét oldal változásainak azonosÃtása és tárolása adatbázis segÃtségével. A törlések és ütközések automatikusan észlelÅ‘dnek. +Idle time between detection of last change and execution of command line in seconds + If you like FFS FFS támogatása Ignore Figyelmen kÃvül hagy -Ignore 1-hour file time difference -1 órás fájl dátum különbségek figyelmen kÃvül hagyása Ignore errors Hibák figyelmen kÃvül hagyása Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v A Shadow Copy a WOW64-en nem támogatott. Kérjük, használja a 64-bites FreeFileSync-et. Match case Kis-/nagybetű egyezés +Minimum Idle Time + Mirror ->> Tükrözés ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: Művelet: Overview Összefoglaló +Overwriting Symbolic Link %x in %y + +Overwriting file %x in %y + Pause Szünet Paused @@ -702,8 +696,6 @@ Remove folder Mappa eltávolÃtása Remove folder pair Mappa párok eltávolÃtása -Removing abandoned directory lock (%x)... - Report translation error FordÃtói hiba bejelentése Reset @@ -846,8 +838,6 @@ Total time: Becsült idÅ‘: Transfer file and directory permissions\n(Requires Administrator rights) Fájlok és mappák jogosultságainak átvitele\n(Adminisztrátori jogok szükségesek) -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 -A fájlok dátumának pontosan +/- 1 órával való eltérése esetén a fájlok egyeznek, a kevesebb mint 1 órával való eltérés esetén pedig ütköznek, a Nyári IdÅ‘számÃtás kezeléséhez Unable to connect to sourceforge.net! A csatlakozás a sourceforge.net-hez sikertelen! Unable to create logfile! diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng index b81c7aa7..6f71202a 100644 --- a/BUILD/Languages/italian.lng +++ b/BUILD/Languages/italian.lng @@ -90,8 +90,6 @@ &Si (Build: %x) (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copia file condivisi o bloccati usando il Servizio Volume Shadow Copy\n(Richiede diritti di Administrator) Copy to clipboard\tCTRL+C Copia nella clipboard\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copia Link Simbolico %x sovrascrivendo %y -Copying Symbolic Link %x to %y -Copia Link Simbolico %x su %y -Copying file %x overwriting %y -Copia file %x sovrascrivendo %y -Copying file %x to %y -Copia di file da %x a %y +Copying new Symbolic Link %x to %y +Copia di nuovo Link Simbolico %x su %y in corso +Copying new file %x to %y +Copia di nuovo file %x su %y in corso Could not determine volume name for file: Impossibile determinare il nome volume per il file: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Errore in verifica data: I file sorgente e destinazione hanno differente contenuto! Date Data -Delay -Ritardo -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 @@ -370,6 +360,8 @@ Elements remaining: Elementi rimanenti: Email Email +Encode extended time information: %x + Endless loop when traversing directory: Loop senza fine attraverso le directory: Error @@ -413,9 +405,9 @@ Errore in lettura dal database di sincronizzione: Error resolving symbolic link: Errore nella risoluzione di collegamento simbolico: Error setting directory lock: - +Errore nell'impostazione del blocco directory: Error setting privilege: -Errore nel settaggio dei privilegi: +Errore nell'impostazione dei privilegi: Error starting Volume Shadow Copy Service! Errore in avvio del Servizio Volume Shadow Copy! Error traversing directory: @@ -460,8 +452,6 @@ File size and date Dimensione e data del file Filename Nome del file -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. -La data dei file %x differisce per meno di 1 ora!\n\nNon è sicuro decidere quale dei due è il più recente con la funzione Daylight Saving Time. Files %x have the same date but a different size! I file %x hanno la stessa data ma dimensione diversa! Files are found equal if\n - file content\nis the same @@ -566,12 +556,12 @@ Homepage Homepage Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identifica e propaga cambiamenti su entrambi i lati usando un database. Cancellazioni e conflitti sono riconosciuti automaticamente. +Idle time between detection of last change and execution of command line in seconds +Tempo di attesa in secondi fra il rilevamento dell'ultima modifica e l'esecuzione della linea di comando If you like FFS Se ti piace FFS Ignore Ignora -Ignore 1-hour file time difference -Ignora la differenza di file time di 1 ora Ignore errors Ignora gli errori Ignore subsequent errors @@ -614,6 +604,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v La creazione di copie shadow su WOW64 non e' supportata. Utilizzare FreeFileSync in versione 64-bit. Match case Corrispondenza +Minimum Idle Time +Tempo di Attesa Minimo Mirror ->> Mirror ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +660,10 @@ Operation: Operazione: Overview Controllo generale +Overwriting Symbolic Link %x in %y +Sovrascrittura di Link Simbolico %x in %y in corso +Overwriting file %x in %y +Sovrascrittura di file %x in %y in corso Pause Pausa Paused @@ -702,8 +698,6 @@ Remove folder Rimuovi cartella Remove folder pair Elimina la coppia di cartelle -Removing abandoned directory lock (%x)... - Report translation error Segnala errori di traduzione Reset @@ -810,8 +804,6 @@ Synchronization completed with errors! Sincronizzazione terminata con errori! Synchronization settings Parametri di sincronizzazione -Synchronization status -Stato della sincronizzazione Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". Sincronizza tutti i file .doc, .zip e .exe eccetto tutti quelli nella cartella \"temp\". Synchronize... @@ -846,8 +838,6 @@ Total time: Tempo totale: Transfer file and directory permissions\n(Requires Administrator rights) Trasferisci file e permessi sulle cartelle\n(Richiede diritti di Administrator) -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 -Tratta file time che differiscono di esattamente +/- 1 ora come uguali, meno di 1 ora come conflitto per gestire i cambiamenti di Daylight Saving Time Unable to connect to sourceforge.net! Impossibile collegarsi a sourceforge.net! Unable to create logfile! @@ -875,7 +865,7 @@ Il nome volume %x non è parte del nome file %y! Waiting for all directories to become available... In attesa che tutte le directory siano disponibili... Waiting while directory is locked (%x)... - +Attendi mentre la directory è bloccata (%x)... Warning Attenzione Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng index 54b13d37..443cca07 100644 --- a/BUILD/Languages/japanese.lng +++ b/BUILD/Languages/japanese.lng @@ -90,8 +90,6 @@ ã¯ã„(&Y) (Build: %x) (ビルド: %x) -(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 @@ -274,13 +272,9 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ ボリュームシャドーコピーを使用ã—ã¦å…±æœ‰/ãƒãƒƒã‚¯ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピー\n(管ç†è€…権é™ãŒå¿…è¦) Copy to clipboard\tCTRL+C クリップボードã«ã‚³ãƒ”ー\tCTRL+C -Copying Symbolic Link %x overwriting %y -シンボリックリンク %x をコピー.. %y ã«ä¸Šæ›¸ãä¸ -Copying Symbolic Link %x to %y -シンボリックリンク %x ã‹ã‚‰ %y ã«ã‚³ãƒ”ãƒ¼ä¸ -Copying file %x overwriting %y -ファイル %x をコピー.. %y ã«ä¸Šæ›¸ãä¸ -Copying file %x to %y +Copying new Symbolic Link %x to %y +シンボリックリンク %x ã‚’ %y ã«ã‚³ãƒ”ãƒ¼ä¸ +Copying new file %x to %y ファイル %x ã‚’ %y ã«ã‚³ãƒ”ãƒ¼ä¸ Could not determine volume name for file: ファイルã®ãƒœãƒªãƒ¥ãƒ¼ãƒ åãŒæ±ºå®šã•ã‚Œã¦ã„ã¾ã›ã‚“: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! データ検証エラー: ソースã¨å¯¾è±¡ãƒ•ã‚¡ã‚¤ãƒ«ã«ç•°ãªã‚‹å†…容ãŒå«ã¾ã‚Œã¦ã„ã¾ã™! Date データ -Delay -é…延時間 -Delay between detection of changes and execution of command line in seconds -変更ã®æ¤œå‡ºã¨ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å®Ÿè¡Œé–“ã®é…延(秒) Delete files/folders existing on left side only å·¦å´ã®ã¿ã«å˜åœ¨ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«/フォルダを削除 Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: åŒæœŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‹ã‚‰ã®èªã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼: Error resolving symbolic link: シンボリックリンクã®è§£æ±ºã«å¤±æ•—: +Error setting directory lock: +ディレクトリè¨å®šã«å¤±æ•—(ãƒãƒƒã‚¯): Error setting privilege: 特権ã®è¨å®šã‚¨ãƒ©ãƒ¼: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date ファイルサイズã¨æ—¥ä»˜ Filename ファイルå -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. -ファイル %x ã®æ™‚é–“ã«ã¯ã€ä¸€æ™‚間未満ã®èª¤å·®ãŒã‚ã‚Šã¾ã™!\n\nå¤æ™‚é–“ã®å•é¡Œã«ã‚ˆã‚Šã€ã‚ˆã‚Šæ–°ã—ã„方を時間ã§æ±ºå®šã™ã‚‹ã®ã¯å®‰å…¨ã§ã¯ã‚ã‚Šã¾ã›ã‚“。 Files %x have the same date but a different size! ファイル %x ã¯ã€åŒã˜æ™‚é–“ã§ã™ãŒã‚µã‚¤ã‚ºãŒç•°ãªã£ã¦ã„ã¾ã™! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage ホームページ Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. データベースを使用ã—ã¦ã€ä¸¡å´ã‚¢ã‚¤ãƒ†ãƒ ã®å¤‰æ›´ã‚’特定ã—ã¾ã™ã€‚ 削除ã€ç«¶åˆã¯è‡ªå‹•çš„ã«æ¤œå‡ºã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +Idle time between detection of last change and execution of command line in seconds +最後ã®å¤‰æ›´ã®æ¤œå‡ºã‹ã‚‰ã€æ¬¡ã«ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã‚’実行ã™ã‚‹ã¾ã§ã®å¾…機時間(秒) If you like FFS FFS ãŒæ°—ã«å…¥ã£ãŸå ´åˆ Ignore 無視 -Ignore 1-hour file time difference -1 時間ã®ãƒ•ã‚¡ã‚¤ãƒ«æ™‚é–“ã®å·®ç•°ã¯ç„¡è¦– Ignore errors エラーを無視 Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v WOW64 ã§ã¯ã€ãƒœãƒªãƒ¥ãƒ¼ãƒ シャドウコピーã«å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“ã€FreeFileSync 64-bit 版をãŠè©¦ã—ãã ã•ã„。 Match case æ–‡å—種を区別 +Minimum Idle Time +最å°å¾…機時間 Mirror ->> ミラー >> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: æ“作: Overview æ¦‚è¦ +Overwriting Symbolic Link %x in %y +シンボリックリンク %x ã‚’ %y ã«ä¸Šæ›¸ãä¸ +Overwriting file %x in %y +ファイル %x ã‚’ %y ã«ä¸Šæ›¸ãä¸ Pause 一時åœæ¢ Paused @@ -842,8 +838,6 @@ Total time: åˆè¨ˆæ™‚é–“: Transfer file and directory permissions\n(Requires Administrator rights) ファイルã¨ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ãƒ‘ーミッション転é€\n(管ç†è€…権é™ãŒå¿…è¦) -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 -ファイルã®æ™‚é–“ã® +/- ã‚’æ£ç¢ºã« 1 時間以上ã®å·®ç•°ã¯ä¸ä¸€è‡´ã€1 時間未満ã®å·®ç•°ã¯åŒæ§˜ãƒ•ã‚¡ã‚¤ãƒ«ã¨ã—ã¦å–り扱ã„ã¾ã™(å¤æ™‚é–“ã¯å¤‰æ›ã•ã‚Œã¾ã™) Unable to connect to sourceforge.net! Sourceforge.net ã«æŽ¥ç¶šã§ãã¾ã›ã‚“! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! ボリュームå %x ã«ãƒ•ã‚¡ã‚¤ãƒ«å %y ã¯ã‚ã‚Šã¾ã›ã‚“! Waiting for all directories to become available... ã™ã¹ã¦ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒåˆ©ç”¨å¯èƒ½ã«ãªã‚‹ã¾ã§å¾…æ©Ÿä¸... +Waiting while directory is locked (%x)... +待機時間ä¸ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¯ãƒãƒƒã‚¯ã•ã‚Œã¾ã™(%x)... Warning è¦å‘Š Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng index d656ea3e..a7e9f143 100644 --- a/BUILD/Languages/polish.lng +++ b/BUILD/Languages/polish.lng @@ -90,8 +90,6 @@ &Tak (Build: %x) (BudujÄ™: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Kopiuj pliki udostÄ™pnione i zablokowane używajÄ…c usÅ‚ugi Volume Shadow Copy\n (Wymaga uprawnieÅ„ administratora) Copy to clipboard\tCTRL+C Kopiuj do pamiÄ™ci\tCTRL+C -Copying Symbolic Link %x overwriting %y -Kopiowanie dowiÄ…zania symbolicznego %x nadpisujÄ…c %y -Copying Symbolic Link %x to %y -Kopiowanie dowiÄ…zania symbolicznego %x do %y -Copying file %x overwriting %y -Kopiowanie pliku %x nadpisujÄ…c %y -Copying file %x to %y -Kopiowanie pliku %x do %y +Copying new Symbolic Link %x to %y +Kopiowanie nowego dowiÄ…zania symbolicznego %x +Copying new file %x to %y +Kopiowanie nowego pliku %x do %y Could not determine volume name for file: Nie można okreÅ›lić nazwy dysku dla pliku: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! BÅ‚Ä…d weryfikacji danych: Plik źródÅ‚owy i docelowy różniÄ… siÄ™ zawartoÅ›ciÄ…! Date Data -Delay -Opóźnienie -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 Delete files/folders existing on right side only @@ -413,7 +403,7 @@ BÅ‚Ä…d odczytu z bazy danych synchronizacji: Error resolving symbolic link: BÅ‚Ä…d odczytu dowiÄ…zania symbolicznego: Error setting directory lock: - +BÅ‚Ä…d ustawiania blokady katalogu: Error setting privilege: BÅ‚Ä…d ustawiania uprawnieÅ„: Error starting Volume Shadow Copy Service! @@ -460,8 +450,6 @@ File size and date Rozmiar i data pliku Filename Nazwa pliku -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. -Pliki %x różniÄ… siÄ™ mniej niż 1 godzinÄ™.\n\nNie można bezpiecznie okreÅ›lić, który plik jest nowszy zgodnie z przesuniÄ™ciem czasu letniego. Files %x have the same date but a different size! Pliki %x majÄ… tÄ… samÄ… datÄ™ lecz różne rozmiary! Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ Homepage Strona domowa Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Wykryj i zastosuj zmiany po obu stronach używajÄ…c bazy danych. UsuniÄ™cia i konflikty sÄ… wykrywane automatycznie. +Idle time between detection of last change and execution of command line in seconds +OdstÄ™p czasu w sekundach pomiÄ™dzy pomiÄ™dzy ostatniÄ… wykrytÄ… zmianÄ…, a wykonaniem komendy If you like FFS Jeżeli Ci siÄ™ podoba Ignore Ignoruj -Ignore 1-hour file time difference -Ignoruj 1-godzinnÄ… różnicÄ™ miÄ™dzy plikami Ignore errors Ignoruj bÅ‚Ä™dy Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Tworzenie Shadow Copies dla WOW64 nie jest obsÅ‚ugiwane. Zainstaluj 64 bitowÄ… wersjÄ™ FreeFileSync. Match case UwzglÄ™dnij wielkość liter +Minimum Idle Time +Minimalny czas bezczynnoÅ›ci Mirror ->> Lustrzana ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: Operacja: Overview PrzeglÄ…d +Overwriting Symbolic Link %x in %y +Nadpisywanie dowiÄ…zania symbolicznego %x, %y +Overwriting file %x in %y +Nadpisywanie pliku %x plikiem %y Pause Pauza Paused @@ -702,8 +696,6 @@ Remove folder UsuÅ„ folder Remove folder pair UsuÅ„ parÄ™ folderów -Removing abandoned directory lock (%x)... - Report translation error ZgÅ‚oÅ› bÅ‚Ä…d w tÅ‚umaczeniu Reset @@ -846,8 +838,6 @@ Total time: CaÅ‚kowity czas: Transfer file and directory permissions\n(Requires Administrator rights) Transfer uprawnieÅ„ plików i katalogów\n(Wymaga uprawnieÅ„ Administratora) -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 -Traktuj pliki różniÄ…ce siÄ™ dokÅ‚adnie +/- 1 godzinÄ™ jako równe, mniej niż 1 godzinÄ™ jako konflikt by uwzglÄ™dnić zmiane czasu letniego Unable to connect to sourceforge.net! Nie można siÄ™ poÅ‚Ä…czyć z sourceforge.net! Unable to create logfile! @@ -875,7 +865,7 @@ Dysk %x nie jest częściÄ… pliku %y! Waiting for all directories to become available... Oczekiwanie aż katalogi stanÄ… siÄ™ dostÄ™pne... Waiting while directory is locked (%x)... - +Blokada katalogu (%x), oczekiwanie... Warning Uwaga Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng index 1f376257..da9f53b3 100644 --- a/BUILD/Languages/portuguese.lng +++ b/BUILD/Languages/portuguese.lng @@ -3,35 +3,35 @@ %x / %y objects deleted successfully %x / %y objectos eliminados com sucesso %x Byte - +%x Byte +%x GB %x GB - %x MB - +%x MB +%x PB %x PB - %x TB - +%x TB %x day(s) - +%x dia(s) %x directories %x pastas %x files %x ficheiros %x hour(s) - +%x hora(s) +%x kB %x kB - %x min - +%x min(s) %x of %y rows in view %x de %y ficheiros %x of 1 row in view %x de 1 linha %x sec - +%x seg(s) +%x% %x% - &Abort &Abortar &About... @@ -85,13 +85,11 @@ &Save &Guardar &Switch - +&Trocar &Yes &Sim (Build: %x) - -(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\".) +(Build: %x) (Requires an Internet connection!) (Necessita acesso à Internet!) - Other side's counterpart to %dir @@ -151,7 +149,7 @@ <Last session> <Última Sessão> <Symlink> - +<Link Simbólico> <multiple selection> <Selecção Múltipla> A newer version of FreeFileSync is available: @@ -197,7 +195,7 @@ Ambos os lados tiveram alterações desde a última sincronização! Browse Procurar Browse directory - +Procurar directório Cannot determine sync-direction: Não é possÃvel saber a direcção de sincronização: Cannot find %x @@ -205,7 +203,7 @@ Não é possÃvel descobrir %x Category Categoria Clear filter settings - +Limpar opções do filtro Comma separated list Lista de itens separados por virgula Command line @@ -257,7 +255,7 @@ Continuar Conversion error: Erro de conversão: Copy filesystem permissions - +Copiar permissões do sistema de ficheiros Copy from left to right Copiar da esquerda para a direita Copy from left to right overwriting @@ -271,17 +269,13 @@ Copiar ficheiros bloqueados 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\n(Requires Administrator rights) - +Copiar ficheiros partilhados ou bloqueados usando o serviço Volume Shadow Copy\n (Requer direitos de administrador) Copy to clipboard\tCTRL+C Copiar para a Ãrea de transferência\tCTRL+C -Copying Symbolic Link %x overwriting %y - -Copying Symbolic Link %x to %y - -Copying file %x overwriting %y - -Copying file %x to %y -Copiar ficheiro %x para %y +Copying new Symbolic Link %x to %y +Copiar novo link simbólico %x para %y +Copying new file %x to %y +Copiar novo ficheiro %x para %y Could not determine volume name for file: Não é possÃvel determinar o nome do volume para o ficheiro: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Erro na verificação de dados: ficheiro fonte e de destino têm conteúdo diferente! Date Data -Delay -Atraso -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 Delete files/folders existing on right side only @@ -327,7 +317,7 @@ Apagar ou substituir ficheiros permanentemente Delete permanently Apagar permanentemente Deleting Symbolic Link %x - +Apagar link simbólico %x Deleting file %x Apagar ficheiro %x Deleting folder %x @@ -337,7 +327,7 @@ Controlo eliminação Description Descrição Direct - +Direto Directories are dependent! Be careful when setting up synchronization rules: Directórios são dependentes! Cuidado ao definir as regras de sincronização: Directories to watch @@ -363,11 +353,11 @@ Fazer download agora? Drag && drop Pegar && largar Elements found: - +ELementos encontrados: Elements processed: - +Elementos processados: Elements remaining: - +Elementos restantes: Email Email Endless loop when traversing directory: @@ -377,7 +367,7 @@ Erro Error changing modification time: Erro ao mudar a hora de modificação: Error copying file permissions: - +Erro ao copiar permissões dos ficheiros: Error copying file: Erro ao copiar ficheiro: Error copying locked file %x! @@ -412,8 +402,10 @@ Error reading from synchronization database: Erro ao ler a base de dados de sincronização: Error resolving symbolic link: Erro na resolução do link simbólico: +Error setting directory lock: +Erro ao bloquear directório: Error setting privilege: - +Erro ao estabelecer privilégios: Error starting Volume Shadow Copy Service! Erro ao iniciar o serviço Volume Shadow Copy! Error traversing directory: @@ -458,8 +450,6 @@ File size and date Data e tamanho do ficheiro Filename Nome do ficheiro -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. -Os ficheiros %x têm uma diferença de tempo inferior a 1 hora!\n\nNão é seguro decidir qual o mais novo devido à s mudanças de Hora de Verão. Files %x have the same date but a different size! Os ficheiros %x têm a mesma data, mas tamanho diferente! Files are found equal if\n - file content\nis the same @@ -473,7 +463,7 @@ Ficheiros existentes dos dois lados, à esquerda é mais recente Files that exist on both sides, right one is newer Ficheiros existentes dos dois lados, à direita é mais recente Files that have different content - +Ficheiros com conteúdo diferente Files/folders that exist on left side only Ficheiros/pastas existentes somente à esquerda Files/folders that exist on right side only @@ -481,15 +471,15 @@ Ficheiros/pastas existentes somente à direita Filter files Filtrar ficheiros Filter is active - +Filtro activo Filter settings have changed! Opções de filtro alteradas! Filter view Filtrar vista Filter: All pairs - +Filtro: Todos os pares Filter: Single pair - +Filtro: Par simples Find Procurar Find what: @@ -497,7 +487,7 @@ Procurar: Folder Comparison and Synchronization Comparação e Sincronização de pastas Follow - +Seguir Free disk space available: Espaço livre em disco: FreeFileSync Batch Job @@ -564,12 +554,12 @@ Homepage Site Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identificar e propagar as mudanças usando base de dados. Eliminações e conflitos serão detectados automaticamente. +Idle time between detection of last change and execution of command line in seconds +Tempo de espera entre a última alteração e a execução do comando em segundos If you like FFS Se gosta do FreeFileSync Ignore - -Ignore 1-hour file time difference -Ignorar diferenças de 1 hora entre ficheiros +Ignorar Ignore errors Ignorar erros Ignore subsequent errors @@ -593,7 +583,7 @@ 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: Invalid FreeFileSync config file! - +Ficheiro de configuração do FreeFileSync inválido! Leave as unresolved conflict Deixar como conflito Left @@ -611,7 +601,9 @@ A escrever em log Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. Fazer cópias fantasma em WOW64 não é suportado. Por favor usar a versão 64-bit. Match case - +Correspondência +Minimum Idle Time +Tempo de espera mÃnimo Mirror ->> Espelhar ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -629,7 +621,7 @@ Mover ficheiros para uma pasta com a data Moving %x to Recycle Bin A mover %x para a Reciclagem Moving Symbolic Link %x to user-defined directory %y - +A mover link simbólico %x para o directório %y Moving file %x to user-defined directory %y A mover ficheiro %x para o directório &y Moving folder %x to user-defined directory %y @@ -659,23 +651,27 @@ Apenas ficheiros/directórios que passem o filtro serão seleccionados para sinc Open with Explorer Abrir com o Explorer Open with default application - +Abrir com a aplicação associada Operation aborted! Operação abortada! Operation: Operação: Overview Vista +Overwriting Symbolic Link %x in %y +Sobrepor link simbólico %x em %y +Overwriting file %x in %y +Sobrepor ficheiro %x em %y Pause Pausa Paused Em pausa Planned directory deletion is in conflict with its subdirectories and -files! - +Eliminação de directorio planeada está em conflito com subdirectorios e/ou ficheiros! Please run a Compare first before synchronizing! Use Comparar antes da primeira sincronização! Press \"Switch\" to open FreeFileSync GUI mode. - +Clique \"Trocar\" para abrir o GUI do FreeFileSync. Processing folder pair: A processar o par do directorio: Published under the GNU General Public License: @@ -785,17 +781,17 @@ Iniciar a sincronização Statistics EstatÃsticas Status feedback - +Retorno de estado Stop Parar Swap sides Trocar lados Switching to FreeFileSync GUI mode... - +A abrir o GUI do FreeFileSync... Symbolic Link handling - +Tratamento de links simbólicos Symlinks %x have the same date but a different target! - +Links simbólicos %x tem a mesma data mas diferente destino! Synchronization Preview Previsualizar sincronização Synchronization aborted! @@ -806,8 +802,6 @@ Synchronization completed with errors! Sincronização completa com erros! Synchronization settings Parâmetros de sincronização -Synchronization status -Estado da sincronização Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". Sincronizar todos os ficheiros .doc, .zip e .exe excepto os da pasta \"temp\". Synchronize... @@ -821,11 +815,11 @@ Directório de destino já existe! Target file already existing! Ficheiro de destino já existe! The command line is executed each time:\n- all directories become available (e.g. USB stick insert)\n- files within these directories or subdirectories are modified - +A linha de comandos é executada cada vez que:\n- os directórios ficam disponÃveis (i.e. pen USB)\n- ficheiros nos directórios ou subdirectórios são modificados The file does not contain a valid configuration: O ficheiro não contém uma configuração válida: The file was not processed by last synchronization! - +O ficheiro não foi processado na última sincronização! 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 avalia dois ficheiros de nome igual como iguais quando têm o mesmo tamanho e a mesma data e hora de modificação. Time @@ -841,9 +835,7 @@ Espaço livre necessário: Total time: Tempo total: Transfer file and directory permissions\n(Requires Administrator rights) - -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 -Tratar ficheiros com exactamente +/- 1 hora como iguais, e menos de 1 hora como conflito, para salvaguardar a alteração da Hora de Verão +Transferir ficheiro e permissões\n(Requer direitos de administrador) Unable to connect to sourceforge.net! Não é possÃvel ligar a sourceforge.net! Unable to create logfile! @@ -869,7 +861,9 @@ A verificar ficheiro %x Volume name %x not part of filename %y! Nome do volume %x não faz parte do ficheiro %y! Waiting for all directories to become available... - +Aguardando que todos os directorios fiquem disponÃveis... +Waiting while directory is locked (%x)... +Aguardando enquanto o directório é bloqueado (%x)... Warning Atenção Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng index 1a84c512..994028eb 100644 --- a/BUILD/Languages/portuguese_br.lng +++ b/BUILD/Languages/portuguese_br.lng @@ -90,8 +90,6 @@ C&riar um arquivo batch... &Sim (Build: %x) (Versão: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copiar arquivos compartilhados ou bloqueados (em uso) usando o Serviço de Cópias de Sombra de Volume\n(Requer direitos de Administrador) Copy to clipboard\tCTRL+C Copiar para a Ãrea de transferência\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copiando Link Simbólico %x substituindo %y -Copying Symbolic Link %x to %y -Copiando Link Simbólico %x para %y -Copying file %x overwriting %y -Copiando arquivo %x substituindo %y -Copying file %x to %y -Copiando arquivo %x para %y +Copying new Symbolic Link %x to %y +Copiando novo Link Simbólico %x para %y +Copying new file %x to %y +Copiando novo arquivo %x para %y 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: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Erro de verificação de dados: Arquivo de origem e destino têm o mesmo conteúdo! Date Data -Delay -Atraso -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 Delete files/folders existing on right side only @@ -413,7 +403,7 @@ Erro ao ler do banco de dados de sincronização: Error resolving symbolic link: Erro na resolução de link simbólico: Error setting directory lock: - +Erro ao definir bloqueio no diretório: Error setting privilege: Erro ao definir privilégio: Error starting Volume Shadow Copy Service! @@ -460,8 +450,6 @@ File size and date Data e tamanho do arquivo Filename Nome do arquivo -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. -Arquivos %x têm diferença no horário de criação menor do que 1 hora!\n\nNão é seguro decidir qual é o mais novo devido a problemas relacionados com o Horário de Verão. Files %x have the same date but a different size! Arquivos %x têm a mesma data mas tamanhos diferentes! Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ 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 utilizando um banco de dados. Exclusões e conflitos serão detectados automaticamente. +Idle time between detection of last change and execution of command line in seconds +Tempo ocioso entre detecção da última mudança e da execução da linha de comando em segundos If you like FFS Se gosta do FFS Ignore Ignorar -Ignore 1-hour file time difference -Ignorar diferenças de 1 hora nos arquivos Ignore errors Ignorar erros Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Cópias de sombra no WOW64 não são suportadas. Por favor use a versão 64-bits do FreeFileSync. Match case Diferenciar maiúsculas e minúsculas +Minimum Idle Time +Tempo Ocioso MÃnimo Mirror ->> Espelhar ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: Operação: Overview Parâmetros +Overwriting Symbolic Link %x in %y +SubstituÃndo Link Simbólico %x em %y +Overwriting file %x in %y +SubstituÃndo arquivo %x em %y Pause Pausa Paused @@ -702,8 +696,6 @@ Remove folder Remover pasta Remove folder pair Remover par de pastas -Removing abandoned directory lock (%x)... - Report translation error Reportar erro de tradução Reset @@ -846,8 +838,6 @@ Total time: Tempo total: Transfer file and directory permissions\n(Requires Administrator rights) Transferir permissões de arquivos e diretórios\n(Requer direitos de Administrador) -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 -Tratar tempo dos arquivos que diferem exatamente por mais ou menos 1 hora como igual e menor que 1 hora como conflito para lidar com mudanças de Horário de Verão Unable to connect to sourceforge.net! Não foi possÃvel conectar a sourceforge.net! Unable to create logfile! @@ -875,7 +865,7 @@ Nome do volume %x não é parte do arquivo %y! Waiting for all directories to become available... Esperando que todos os diretóricos fiquem disponÃveis... Waiting while directory is locked (%x)... - +Esperando enquanto o diretório é travado (%x)... Warning Atenção Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng index 7bb1bb92..a5f860af 100644 --- a/BUILD/Languages/romanian.lng +++ b/BUILD/Languages/romanian.lng @@ -90,8 +90,6 @@ &Da (Build: %x) (Compilarea: %x) -(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, poÈ›i dezactiva setarea \"ignoră diferenÈ›a de 1-oră\".) (Requires an Internet connection!) (Necesită o conexiune la internet!) - Other side's counterpart to %dir @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copiază filele partajate sau zăvorîte folosind Serviciul de Salvgardare a Volumelor [Volume Shadow Copy]\n(Necesită drepturi de Administrator) Copy to clipboard\tCTRL+C Copiază în CliplanÈ™etă\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copiez legătura simbolică %x È™i suprascriu %y -Copying Symbolic Link %x to %y -Copiez legătura simbolică %x în %y -Copying file %x overwriting %y -Copiez fila %x È™i suprascriu %y -Copying file %x to %y -Copiez fila %x în %y +Copying new Symbolic Link %x to %y +Copiez noua Legătură Simbolică %x în %y +Copying new file %x to %y +Copiez noua filă %x în %y Could not determine volume name for file: Nu pot determina numele volumului pentru fila: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Eroare la verificarea datelor: Filele sursă È™i È›intă au conÈ›inut diferit! Date Dată -Delay -ÃŽntîrziere -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 Delete files/folders existing on right side only @@ -413,7 +403,7 @@ Eroare la citirea din baza de date a sincronizării: Error resolving symbolic link: Eroare la rezolvarea legăturii simbolice: Error setting directory lock: - +Eroare la efectuarea zăvorîrii dosarului: Error setting privilege: Eroare la setarea privilegiului: Error starting Volume Shadow Copy Service! @@ -460,8 +450,6 @@ File size and date Mărimea È™i Data Filei Filename Numele Filei -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. -Filele %x au o diferență de dată mai mică de 1 oră!\n\nNu este clar care e mai nouă, din cauza problemelor cauzate de ora de vară. Files %x have the same date but a different size! Filele %x au aceeaÈ™i dată, dar mărime diferită! Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ Homepage Sit Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Identifică È™i propagă modificările în ambele părÈ›i folosind o bază de date. Ștergerile È™i conflictele sînt detectate automat. +Idle time between detection of last change and execution of command line in seconds +Timp de inactivitate (în secunde) între detectarea ulimei modificări È™i executarea liniei de comandă If you like FFS Donare pentru FFS Ignore Ignoră -Ignore 1-hour file time difference -Ignoră diferenÈ›ele de 1 oră ale timpurilor filelor Ignore errors Ignoră erorile Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Realizarea de copii de rezervă prin sistemul WOW64 nu este suportată. FoloseÈ™te versiunea pe 64-biÈ›i a FreeFileSync. Match case PotriveÈ™te MAJ/min +Minimum Idle Time +Timp Minim de Inactivitate Mirror ->> Clonare =>> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: OperaÈ›iune: Overview Panoramă +Overwriting Symbolic Link %x in %y +Suprascriu Legătura Simbolică %x în %y +Overwriting file %x in %y +Suprascriu fila %x în %y Pause Pauză Paused @@ -702,8 +696,6 @@ Remove folder ÃŽnlătură Dosarul Remove folder pair ÃŽnlătură Perechea de Dosare -Removing abandoned directory lock (%x)... - Report translation error Raportarea erorilor de traducere Reset @@ -846,8 +838,6 @@ Total time: Timp Total: Transfer file and directory permissions\n(Requires Administrator rights) Transferă permisiunile filelor È™i dosarelor\n(Necesită drepturi de Administrator) -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 -Tratează ca egale timpurile filelor care diferă exact cu +/- 1 oră, iar cele care diferă cu mai puÈ›in de 1 oră, ca niÈ™te conflicte generate de gestionarea orei de vară Unable to connect to sourceforge.net! Conectarea la situl sourceforge.net nu poate fi realizată! Unable to create logfile! @@ -875,7 +865,7 @@ Numele volumului %x nu face parte din numele filei %y ! Waiting for all directories to become available... AÈ™tept ca toate dosarele să devină disponibile... Waiting while directory is locked (%x)... - +AÈ™tept ca dosarul să fie zăvorît (%x)... Warning Avertisment Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng index 5e588273..99c85a1c 100644 --- a/BUILD/Languages/russian.lng +++ b/BUILD/Languages/russian.lng @@ -13,23 +13,23 @@ %x TB %x ТБ %x day(s) - +%x дн. %x directories %x папки %x files %x файл(ов) %x hour(s) - +%x ч %x kB %x кБ %x min - +%x мин %x of %y rows in view %x из %y Ñтрок(и) показано %x of 1 row in view %x из 1 Ñтрока показана %x sec - +%x Ñ %x% %x% &Abort @@ -89,11 +89,9 @@ &Yes &Да (Build: %x) -(Сборка %x) -(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-чаÑовую разницу\".) +(Ñборка %x) (Requires an Internet connection!) -(ТребуетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ к Интернету!) +(требуетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ к Интернету!) - Other side's counterpart to %dir - Ð°Ð½Ð°Ð»Ð¾Ð³Ð¸Ñ‡Ð½Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ Ñтороны - Other side's counterpart to %name @@ -257,31 +255,27 @@ Continue Conversion error: Ошибка преобразованиÑ: Copy filesystem permissions - +Копировать права доÑтупа файловой ÑиÑтемы Copy from left to right -Скопировать Ñлева направо +Копировать Ñлева направо Copy from left to right overwriting -Скопировать Ñлева направо Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñью +Копировать Ñлева направо Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñью 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\n(Requires Administrator rights) - +Копирование общих или заблокированных файлов\nÑ Ð¸Ñпользованием Ñлужбы Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°\n(требуютÑÑ Ð¿Ñ€Ð°Ð²Ð° ÐдминиÑтратора) Copy to clipboard\tCTRL+C Копировать в буфер обмена\tCTRL+C -Copying Symbolic Link %x overwriting %y -Копирование Ñимвольной ÑÑылки %x Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñью %y -Copying Symbolic Link %x to %y -Копирование Ñимовльной ÑÑылки %x в %y -Copying file %x overwriting %y -Копирование файла %x Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñью %y -Copying file %x to %y -Копирование файла %x в %y +Copying new Symbolic Link %x to %y +Копирование новой Ñимвольной ÑÑылки %x в %y +Copying new file %x to %y +Копирование нового файла %x в %y Could not determine volume name for file: Ðе удалоÑÑŒ определить название тома Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð°: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Ошибка проверки данных: иÑходный и конечный файлы имеют разное Ñодержание! Date Дата -Delay -Задержка -Delay between detection of changes and execution of command line in seconds -Задержка между обнаружением изменений и выполнением командной Ñтроки в Ñекундах Delete files/folders existing on left side only УдалÑÑ‚ÑŒ файлы/папки, ÑущеÑтвующие только на левой Ñтороне Delete files/folders existing on right side only @@ -370,6 +360,8 @@ Elements remaining: Ðлементов оÑталоÑÑŒ: Email Почта +Encode extended time information: %x + Endless loop when traversing directory: Зацикливание при вÑтрече переÑекающихÑÑ Ð¿ÑƒÑ‚ÐµÐ¹: Error @@ -377,7 +369,7 @@ Error Error changing modification time: Ошибка при изменении времени модификации файла: Error copying file permissions: - +Ошибка при копировании прав доÑтупа: Error copying file: Ошибка при копировании файла: Error copying locked file %x! @@ -412,10 +404,12 @@ Error reading from synchronization database: Ошибка при чтении из базы данных Ñинхронизации: Error resolving symbolic link: Ошибка при решении ÑимволичеÑкой ÑÑылки: +Error setting directory lock: +Ошибка блокировки папки: Error setting privilege: - +Ошибка уÑтановки привилегий: Error starting Volume Shadow Copy Service! -Ошибка при запуÑке Службы Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°! +Ошибка при запуÑке Ñлужбы Теневого ÐšÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¢Ð¾Ð¼Ð°! Error traversing directory: Ошибка при переÑечении папок: Error when monitoring directories. @@ -458,8 +452,6 @@ File size and date Размер и дата файла Filename Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° -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. -Файлы %x имеют Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚Ð»Ð¸Ñ‡Ð°ÑŽÑ‰ÐµÐµÑÑ Ð¼ÐµÐ½ÐµÐµ чем на 1 чаÑ!\n\nРешать какой новее небезопаÑно ввиду перехода на летнее времÑ. Files %x have the same date but a different size! Файлы %x имеют одинаковую дату, но различаютÑÑ Ð¿Ð¾ размеру! Files are found equal if\n - file content\nis the same @@ -564,12 +556,12 @@ Homepage Оф.Ñайт Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Ð’Ñ‹Ñвление и раÑпроÑтранение изменений на обеих Ñторонах Ñ Ð¸Ñпользованием базы данных. Удаленные файлы и конфликты определÑÑŽÑ‚ÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки. +Idle time between detection of last change and execution of command line in seconds +Ð’Ñ€ÐµÐ¼Ñ Ð¿Ñ€Ð¾ÑÑ‚Ð¾Ñ Ð¼ÐµÐ¶Ð´Ñƒ обнаружением поÑледнего Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸ выполнением командной Ñтроки в Ñекундах If you like FFS ЕÑли Вам понравилÑÑ FFS Ignore Игнорировать -Ignore 1-hour file time difference -Игнорировать 1-чаÑовую разницу во времени Ignore errors Игнорировать ошибки Ignore subsequent errors @@ -593,7 +585,7 @@ Initial synchronization: Integrate external applications into context menu. The following macros are available: Интегрирует внешние Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² контекÑтное меню.\nСледующие команды доÑтупны: Invalid FreeFileSync config file! - +Ðеверный файл конфигурации FreeFileSync! Leave as unresolved conflict ОÑтавить как нерешенный конфликт Left @@ -612,6 +604,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Создание теневых копий на WOW64 не поддерживаетÑÑ. ПожалуйÑта, иÑпользуйте FreeFileSync 64-разрÑдной верÑии. Match case Учитывать региÑÑ‚Ñ€ +Minimum Idle Time +Минимальное Ð²Ñ€ÐµÐ¼Ñ Ð¿Ñ€Ð¾ÑÑ‚Ð¾Ñ Mirror ->> Зеркало ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +660,10 @@ Operation: ОперациÑ: Overview Ð“Ð»Ð°Ð²Ð½Ð°Ñ +Overwriting Symbolic Link %x in %y +ПерезапиÑÑŒ Ñимвольной ÑÑылки %x в %y +Overwriting file %x in %y +ПерезапиÑÑŒ файла %x в %y Pause Пауза Paused @@ -806,8 +804,6 @@ Synchronization completed with errors! Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð·Ð°ÐºÐ¾Ð½Ñ‡ÐµÐ½Ð° Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸! Synchronization settings ÐаÑтройки Ñинхронизации -Synchronization status -Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñинхронизации Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". Синхронизировать вÑе .doc, .zip и .exe файлы, за иÑключением вÑех файлов из подпапки \"temp\" Synchronize... @@ -841,9 +837,7 @@ Total required free disk space: Total time: Общее времÑ: Transfer file and directory permissions\n(Requires Administrator rights) - -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 -Учитывать файлы, которые отличаютÑÑ Ð¿Ð¾ времени на 1 чаÑ, как равные, менее чем на 1 чаÑ, как конфликтные, чтобы учеÑÑ‚ÑŒ переход на летнее Ð²Ñ€ÐµÐ¼Ñ +Передача прав доÑтупа файла/папки\n(требуютÑÑ Ð¿Ñ€Ð°Ð²Ð° ÐдминиÑтратора) Unable to connect to sourceforge.net! Ðевозможно ÑоединитьÑÑ Ñ sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Ð˜Ð¼Ñ Ñ‚Ð¾Ð¼Ð° %x не ÑвлÑетÑÑ Ñ‡Ð°Ñтью имени файла %y! Waiting for all directories to become available... Ожидание, пока вÑе папки Ñтанут доÑтупными... +Waiting while directory is locked (%x)... +Ожидание ÑнÑÑ‚Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ Ñ Ð¿Ð°Ð¿ÐºÐ¸ (%x)... Warning Внимание Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng index 72c1b604..4fc220d8 100644 --- a/BUILD/Languages/slovenian.lng +++ b/BUILD/Languages/slovenian.lng @@ -90,14 +90,12 @@ Na&loži konfiguracijo... &Da (Build: %x) (Izgradnja: %x) -(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 -Duplikat z druge strani od %dir +- Duplikat z druge strani od %dir - Other side's counterpart to %name -Duplikat z druge strani od %name +- Duplikat z druge strani od %name - conflict - spor - conflict (same date, different size) @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Kopiraj deljene ali zaklenjene datoteke z uporabo servisa Shadow Copy\n(Zahteva pravice skrbnika) Copy to clipboard\tCTRL+C Kopiraj v odložiÅ¡Äe\tCTRL+C -Copying Symbolic Link %x overwriting %y -Kopiram simboliÄno povezavo %x s prepisovanjem %y -Copying Symbolic Link %x to %y -Kopiram simboliÄno povezavo %x v %y -Copying file %x overwriting %y -Kopiram datoteko %x s prepisovanjem %y -Copying file %x to %y -Kopiram datoteko %x v %y +Copying new Symbolic Link %x to %y +Kopiram novo SimboliÄno povezavo %x v %y +Copying new file %x to %y +Kopiram novo datoteko %x v %y Could not determine volume name for file: Ne morem doloÄiti imena volumna za datoteko: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Napaka pri preverjanju podatkov: izvorna in ciljna datoteka imata razliÄno vsebino! Date Datum -Delay -Zakasnitev -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 Delete files/folders existing on right side only @@ -413,7 +403,7 @@ Napaka pri branju iz sinhronizacijske podatkovne baze: Error resolving symbolic link: Napaka pri razreÅ¡evanju simboliÄne povezave: Error setting directory lock: - +Napaka pri nastavljanju zaklepanja imenika: Error setting privilege: Napaka pri nastavljanju privilegija: Error starting Volume Shadow Copy Service! @@ -460,8 +450,6 @@ File size and date Velikosti in datumu datoteke Filename Ime datoteke -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. -Datoteki %x imata razliko v Äasu spremembe manj kot 1 uro!\n\nNi se varno odloÄiti katera je novejÅ¡a zaradi vpraÅ¡anj v zvezi s Poletnim Äasom. Files %x have the same date but a different size! Datoteki %x imata enak datum ampak razliÄno velikost! Files are found equal if\n - file content\nis the same @@ -566,12 +554,12 @@ Homepage DomaÄa stran Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. Prepoznaj in Å¡iri spremembe na obeh straneh z uporabo podatkovne baze. Izbrisi in spori so zaznani samodejno. +Idle time between detection of last change and execution of command line in seconds +ÄŒas nedejavnosti med zaznavanjem zadnje spremembe in izvrÅ¡itvijo ukazne vrstice v sekundah If you like FFS ÄŒe vam je FFS vÅ¡eÄ Ignore Ignoriraj -Ignore 1-hour file time difference -Ignoriraj 1-urno Äasovno razliko Ignore errors Ignoriraj napake Ignore subsequent errors @@ -614,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Ustvarjanje senÄnih kopij na WOW63 ni podprto. Prosimo uporabite 64-bitno FreeFileSync razliÄico. Match case Ujemaj se s primerom +Minimum Idle Time +Minimalni Äas nedejavnosti Mirror ->> Zrcalno ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -668,6 +658,10 @@ Operation: Operacija: Overview Pregled +Overwriting Symbolic Link %x in %y +Prepisujem SimboliÄno povezavo %x v %y +Overwriting file %x in %y +Prepisujem datoteko %x v %y Pause Premor Paused @@ -702,8 +696,6 @@ Remove folder Odstrani v mapo Remove folder pair Odstrani par imenikov -Removing abandoned directory lock (%x)... - Report translation error PoroÄaj o napaki prevoda Reset @@ -846,8 +838,6 @@ Total time: Celoten Äas: Transfer file and directory permissions\n(Requires Administrator rights) Prenesi dovoljenja datotek in imenikov\n(Zahteva pravice skrbnika) -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 -Obravnavaj Äas spremembe datoteke, ki se razlikuje za toÄno +/- 1 uro kot enak, Äe pa je manjÅ¡i kot 1 ura, pa kot spor, da lahko obravnavamo spremembe Poletnega Äasa Unable to connect to sourceforge.net! Ne morem se povezati na sourceforge.net! Unable to create logfile! @@ -875,7 +865,7 @@ Ime volumna %x ni del imena datoteke %y! Waiting for all directories to become available... ÄŒakam, da bodo vsi imeniki na voljo... Waiting while directory is locked (%x)... - +ÄŒakam, medtem ko se zaklepa imenik (%x)... Warning Pozor Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng index 92792843..9243158f 100644 --- a/BUILD/Languages/spanish.lng +++ b/BUILD/Languages/spanish.lng @@ -13,23 +13,23 @@ %x TB %x TB %x day(s) - +%x dia(s) %x directories %x directorios %x files %x archivos %x hour(s) - +%x hora(s) %x kB %x kB %x min - +%x min %x of %y rows in view %x de %y filas en vista %x of 1 row in view %x de 1 fila en vista %x sec - +%x seg %x% %x% &Abort @@ -90,8 +90,6 @@ &Si (Build: %x) (Completado: %x) -(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 @@ -257,7 +255,7 @@ Continuar Conversion error: Error de conversión: Copy filesystem permissions - +Permisos de copia del sistema de ficheros Copy from left to right Copiar de izquierda a derecha Copy from left to right overwriting @@ -271,17 +269,13 @@ Copiar archivos bloqueados Copy new or updated files to right folder. Copiar archivos nuevos o actualizados a la carpeta de la derecha. Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administrator rights) - +Copiar archivos compartidos o bloqueados usando el servicio "Volume Shadow Copy"\n(Requiere derechos de administrador) Copy to clipboard\tCTRL+C Copiar al Portapapeles\tCTRL+C -Copying Symbolic Link %x overwriting %y -Copiando enlace simbólico %x y sobreescribiendo %y -Copying Symbolic Link %x to %y -Copiando enlace simbólico %x a %y -Copying file %x overwriting %y -Copiando archivo %x y sobreescribiendo %y -Copying file %x to %y -Copiar archivo %x a %y +Copying new Symbolic Link %x to %y +Copiando enlace simbólico nuevo de %x a %y +Copying new file %x to %y +Copiando archivo nuevo de %x a %y Could not determine volume name for file: No se ha podido determinar el nombre del volumen para el archivo: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Error de verificación de datos: ¡Los archivos de origen y destino tienen un contenido diferente! Date Fecha -Delay -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 Borrar sólo archivos/carpetas existentes en el lado izquierdo Delete files/folders existing on right side only @@ -377,7 +367,7 @@ Error Error changing modification time: Error al cambiar hora de modificación: Error copying file permissions: - +Error al copiar permisos del fichero: Error copying file: Error al copiar archivo: Error copying locked file %x! @@ -412,8 +402,10 @@ Error reading from synchronization database: Error al leer de la base de datos de sincronización: Error resolving symbolic link: Error al resolver enlace simbólico: +Error setting directory lock: +Error al establecer bloqueo del directorio: Error setting privilege: - +Error al establecer privilegios: Error starting Volume Shadow Copy Service! ¡Error al iniciar el servicio "Volume Shadow Copy"! Error traversing directory: @@ -458,8 +450,6 @@ File size and date Fecha y tamaño del archivo Filename 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 referentes al 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 @@ -564,12 +554,12 @@ 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. Las eliminaciones y los conflictos se detectan automáticamente. +Idle time between detection of last change and execution of command line in seconds +Tiempo de inactividad entre la detección del último cambio y la ejecución de la lÃnea de comandos en segundos If you like FFS Si te gusta FFS Ignore Ignorar -Ignore 1-hour file time difference -Ignorar el archivo de 1-hora de tiempo de diferencia Ignore errors Ignorar errores Ignore subsequent errors @@ -593,7 +583,7 @@ Sincronización inicial: Integrate external applications into context menu. The following macros are available: Integrar aplicaciones externas en el menú de contexto. Los siguientes macros están disponibles: Invalid FreeFileSync config file! - +¡Archivo de configuración de FreeFileSync inválido! Leave as unresolved conflict Dejar como conflicto sin resolver Left @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v La realización de copias shadow en WOW64 no está soportado. Por favor, use la versión 64-bit de FreeFileSync. Match case Distinción entre mayúsculas y minúsculas +Minimum Idle Time +Tiempo de inactividad mÃnimo Mirror ->> Espejo ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Operación: Overview Visión global +Overwriting Symbolic Link %x in %y +Sobreescribiendo enlace simbólico %x en %y +Overwriting file %x in %y +Sobreescribiendo archivo %x en %y Pause Pausa Paused @@ -841,9 +837,7 @@ Espacio total de disco necesario: Total time: Tiempo total: Transfer file and directory permissions\n(Requires Administrator rights) - -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 -El archivo en cuestión tiene una diferencia de tiempo de +/- 1 hora, menos de una hora entra en conflicto para gestionar los cambios referentes al horario de verano +Transferir permisos de archivo y directorio\n(Requiere derechos de administrador) Unable to connect to sourceforge.net! ¡Incapaz de conectar con sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! El nombre del volumen %x no es una parte del nombre de archivo %y Waiting for all directories to become available... Esperando a que todos los directorios esten disponibles... +Waiting while directory is locked (%x)... +Esperando mientras el directorio se encuentre bloqueado (%x)... Warning Atención Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng index 9e4b4a9e..6462f5c3 100644 --- a/BUILD/Languages/swedish.lng +++ b/BUILD/Languages/swedish.lng @@ -89,9 +89,7 @@ &Yes &Ja (Build: %x) -(Bygg: %x) -(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\".) +(Bygge: %x) (Requires an Internet connection!) (Kräver Internetuppkoppling!) - Other side's counterpart to %dir @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Kopiera delade eller lÃ¥sta filer med hjälp av Volume Shadow Copy Service\n(Kräver administratörsrättighet) Copy to clipboard\tCTRL+C Kopiera till urklipp\tCTRL+C -Copying Symbolic Link %x overwriting %y -Kopierar symbolisk länk %x skriver över %y -Copying Symbolic Link %x to %y -Kopierar symbolisk länk %x till %y -Copying file %x overwriting %y -Kopierar fil %x skriver över %y -Copying file %x to %y -Kopierar fil %x till %y +Copying new Symbolic Link %x to %y +Kopierar ny symbolisk länk %x to %y +Copying new file %x to %y +Kopierar ny fil %x till %y Could not determine volume name for file: Kan inte bestämma volym för fil: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ 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 @@ -412,6 +402,8 @@ Error reading from synchronization database: Kan inte läsa frÃ¥n databasen: Error resolving symbolic link: Kan inte tyda symbolisk länk: +Error setting directory lock: +Kan inte lÃ¥sa katalogen: Error setting privilege: Kan inte ange privilegie: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ 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 @@ -564,12 +554,12 @@ 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. +Idle time between detection of last change and execution of command line in seconds +Väntetid mellan upptäckt av senaste ändring och verkställande av kommando, i sekunder If you like FFS Om du gillar FFS Ignore Ignorera -Ignore 1-hour file time difference -Ignorera sommartid Ignore errors Ignorera fel Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Skuggkopior av wow64 stöds ej. Använd FreeFileSync x64 istället! Match case Matcha gemener/VERSALER +Minimum Idle Time +Minsta väntetid Mirror ->> Spegla ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Arbetsuppgift: Overview Översikt +Overwriting Symbolic Link %x in %y +Skriver över symbolisk länk %x i %y +Overwriting file %x in %y +Skriver över fil %x i %y Pause Paus Paused @@ -725,7 +721,7 @@ Markera en katalog Select alternate synchronization settings Välj alternativa synkroniseringsinställningar Select logfile directory: -Välj loggfilsdestination: +Välj loggfilskatalog: Select variant: Välj variant: Set direction: @@ -842,8 +838,6 @@ Total time: Total tid: Transfer file and directory permissions\n(Requires Administrator rights) Överför fil- och katalogrättigheter\n(Kräver administratörsrättigheter) -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 Unable to connect to sourceforge.net! Kan inte ansluta sourceforge.net! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! Volymnamn %x saknas i filnamn %y! Waiting for all directories to become available... Väntar pÃ¥ att alla sökvägar skall bli Ã¥tkommliga... +Waiting while directory is locked (%x)... +Väntar medan katalogen lÃ¥ses (%x)... Warning Varning Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng index 8971e84c..ad8d7c19 100644 --- a/BUILD/Languages/turkish.lng +++ b/BUILD/Languages/turkish.lng @@ -90,8 +90,6 @@ Ge&ri yükle &Evet (Build: %x) -(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 @@ -274,14 +272,10 @@ Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administ Copy to clipboard\tCTRL+C Hafızaya kopyala\tCTRL+C -Copying Symbolic Link %x overwriting %y +Copying new Symbolic Link %x to %y -Copying Symbolic Link %x to %y +Copying new file %x to %y -Copying file %x overwriting %y - -Copying file %x to %y -%x'den %y'e dosya kopyalanıyor Could not determine volume name for file: Belirtilen dosya için birim adı belirlenemedi: Could not initialize directory monitoring: @@ -308,10 +302,6 @@ Data verification error: Source and target file have different content! Veri doÄŸrulama hatası: Kaynak ve hedef dosyası içeriÄŸi farklı! Date Tarih -Delay -Gecikme -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 Delete files/folders existing on right side only @@ -412,6 +402,8 @@ Error reading from synchronization database: Senkronizasyon veri tabanýndan okuma hatasý: Error resolving symbolic link: Sembolik baÄŸlantıyı çözümlerken hata: +Error setting directory lock: + Error setting privilege: Error starting Volume Shadow Copy Service! @@ -458,8 +450,6 @@ File size and date Dosya ebatı ve tarihi Filename Dosya adı -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. -%X dosyaları 1 saat'ten daha az tarih farkına sahip!\n\Gün ışığından yararlanma ayarına baÄŸlı olarak hangisinin daha yeni olduÄŸuna karar vermek güvenli deÄŸil. Files %x have the same date but a different size! %x dosyalarının tarihleri aynı fakat ebatları farklı! Files are found equal if\n - file content\nis the same @@ -564,12 +554,12 @@ Homepage Ana sayfa Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. +Idle time between detection of last change and execution of command line in seconds + If you like FFS EÄŸer FFS’i sevdiyseniz Ignore -Ignore 1-hour file time difference -1 saatlik dosya tarihi farklılaÅŸmasını yoksay Ignore errors Hataları yoksay Ignore subsequent errors @@ -612,6 +602,8 @@ Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit v Match case +Minimum Idle Time + Mirror ->> Yedekleme ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. @@ -666,6 +658,10 @@ Operation: Ä°ÅŸlem: Overview DeÄŸerlendirme +Overwriting Symbolic Link %x in %y + +Overwriting file %x in %y + Pause Duraklat Paused @@ -842,8 +838,6 @@ Total time: Toplam zaman: Transfer file and directory permissions\n(Requires Administrator rights) -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 -Dosya tarihleri tam olarak +/- 1 saat farklı olduÄŸunda dosyaları eÅŸit olarak algıla. 1 saatten az tarih farklılıklarını ise tutarsızlık olarak belirt (Gün ışığından yararlanma durumu) Unable to connect to sourceforge.net! sourceforge.net’e baÄŸlanılamıyor! Unable to create logfile! @@ -870,6 +864,8 @@ Volume name %x not part of filename %y! %x birim adı, %y dosya adının bölümü deÄŸil! Waiting for all directories to become available... +Waiting while directory is locked (%x)... + Warning Uyarı Warning: Synchronization failed for %x item(s): diff --git a/BUILD/Resources.dat b/BUILD/Resources.dat Binary files differindex 42cbfb40..be5fa75e 100644 --- a/BUILD/Resources.dat +++ b/BUILD/Resources.dat diff --git a/FreeFileSync - wxWidgets v2.9.1 Beta.vcxproj b/FreeFileSync - wxWidgets v2.9.1 Beta.vcxproj index 6fe2a80e..dffb1560 100644 --- a/FreeFileSync - wxWidgets v2.9.1 Beta.vcxproj +++ b/FreeFileSync - wxWidgets v2.9.1 Beta.vcxproj @@ -100,10 +100,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-2.9.1\include;C:\Programme\C++\wxWidgets-2.9.1\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)library\pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4996;4100;</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -135,10 +135,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)library\pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4996;4100;</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -172,10 +172,10 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-2.9.1\include;C:\Programme\C++\wxWidgets-2.9.1\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> + <DisableSpecificWarnings>4996;4100;</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> @@ -206,10 +206,10 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4996;4100;</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> @@ -260,7 +260,8 @@ <ClCompile Include="shared\custom_combo_box.cpp" /> <ClCompile Include="shared\custom_tooltip.cpp" /> <ClCompile Include="shared\dll_loader.cpp" /> - <ClCompile Include="shared\drag_n_drop.cpp" /> + <ClCompile Include="shared\dir_name.cpp" /> + <ClCompile Include="shared\dst_hack.cpp" /> <ClCompile Include="shared\file_handling.cpp" /> <ClCompile Include="shared\file_id.cpp" /> <ClCompile Include="shared\file_io.cpp" /> diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp index a8e8709d..d7a6c432 100644 --- a/FreeFileSync.cbp +++ b/FreeFileSync.cbp @@ -28,7 +28,7 @@ <Add library="libwxpng.a" /> <Add library="libwxzlib.a" /> <Add library="libwxbase28u_net.a" /> - <Add library="libboost_thread-mgw45-mt-s-1_43.a" /> + <Add library="libboost_thread-mgw45-mt-s-1_44.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> </Linker> </Target> @@ -54,7 +54,7 @@ <Add library="libwxbase28ud.a" /> <Add library="libwxpngd.a" /> <Add library="libwxzlibd.a" /> - <Add library="libboost_thread-mgw45-mt-sd-1_43.a" /> + <Add library="libboost_thread-mgw45-mt-sd-1_44.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll" /> </Linker> </Target> @@ -77,7 +77,7 @@ <Add library="libwxmsw28ud_core.a" /> <Add library="libwxbase28ud.a" /> <Add library="libwxbase28ud_net.a" /> - <Add library="libboost_thread-mgw45-mt-sd-1_43.a" /> + <Add library="libboost_thread-mgw45-mt-sd-1_44.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll" /> </Linker> </Target> @@ -98,7 +98,7 @@ <Add option="-DFFS_WIN" /> <Add option="-DTIXML_USE_STL" /> <Add option="-DwxUSE_UNICODE" /> - <Add option="-DZSTRING_WIDE_CHAR" /> + <Add option="-DBOOST_THREAD_USE_LIB" /> <Add directory="C:\Programme\C++\wxWidgets\include" /> <Add directory="C:\Program Files\C++\Boost" /> </Compiler> @@ -240,6 +240,7 @@ <Option target="Release" /> <Option target="Debug-DLL" /> </Unit> + <Unit filename="shared\boost_thread_wrap.h" /> <Unit filename="shared\build_info.h" /> <Unit filename="shared\check_exist.cpp" /> <Unit filename="shared\check_exist.h" /> @@ -261,17 +262,12 @@ <Option target="Release" /> <Option target="Debug-DLL" /> </Unit> - <Unit filename="shared\debug_new.h" /> + <Unit filename="shared\dir_name.cpp" /> + <Unit filename="shared\dir_name.h" /> <Unit filename="shared\dll_loader.cpp" /> <Unit filename="shared\dll_loader.h" /> - <Unit filename="shared\drag_n_drop.cpp"> - <Option target="Release" /> - <Option target="Debug-DLL" /> - </Unit> - <Unit filename="shared\drag_n_drop.h"> - <Option target="Release" /> - <Option target="Debug-DLL" /> - </Unit> + <Unit filename="shared\dst_hack.cpp" /> + <Unit filename="shared\dst_hack.h" /> <Unit filename="shared\file_error.h" /> <Unit filename="shared\file_handling.cpp" /> <Unit filename="shared\file_handling.h" /> @@ -295,8 +291,6 @@ </Unit> <Unit filename="shared\localization.cpp" /> <Unit filename="shared\localization.h" /> - <Unit filename="shared\lock.cpp" /> - <Unit filename="shared\lock.h" /> <Unit filename="shared\long_path_prefix.cpp" /> <Unit filename="shared\long_path_prefix.h" /> <Unit filename="shared\recycler.cpp" /> @@ -336,6 +330,7 @@ <Unit filename="shared\xml_base.cpp" /> <Unit filename="shared\xml_base.h" /> <Unit filename="shared\xml_error.h" /> + <Unit filename="shared\zbase.h" /> <Unit filename="shared\zstring.cpp" /> <Unit filename="shared\zstring.h" /> <Unit filename="structures.cpp" /> diff --git a/FreeFileSync.vcxproj b/FreeFileSync.vcxproj index 05ee798f..2d17e319 100644 --- a/FreeFileSync.vcxproj +++ b/FreeFileSync.vcxproj @@ -100,10 +100,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets\include;C:\Programme\C++\wxWidgets\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)library\pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -135,10 +135,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)library\pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -172,13 +172,14 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets\include;C:\Programme\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> + <InlineFunctionExpansion>Default</InlineFunctionExpansion> </ClCompile> <Link> <SubSystem>Windows</SubSystem> @@ -206,10 +207,10 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> @@ -226,6 +227,7 @@ <AdditionalLibraryDirectories>C:\Programme\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> <LinkStatus> </LinkStatus> + <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> </Link> <ResourceCompile> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets\include;C:\Programme\C++\wxWidgets\lib\vc_lib\mswu</AdditionalIncludeDirectories> @@ -260,7 +262,8 @@ <ClCompile Include="shared\custom_combo_box.cpp" /> <ClCompile Include="shared\custom_tooltip.cpp" /> <ClCompile Include="shared\dll_loader.cpp" /> - <ClCompile Include="shared\drag_n_drop.cpp" /> + <ClCompile Include="shared\dir_name.cpp" /> + <ClCompile Include="shared\dst_hack.cpp" /> <ClCompile Include="shared\file_handling.cpp" /> <ClCompile Include="shared\file_id.cpp" /> <ClCompile Include="shared\file_io.cpp" /> @@ -5,8 +5,8 @@ BINDIR = $(DESTDIR)$(prefix)/bin SHAREDIR = $(DESTDIR)$(prefix)/share APPSHAREDIR = $(SHAREDIR)/$(APPNAME) -FFS_CPPFLAGS=-Wall -pipe -DNDEBUG -DwxUSE_UNICODE `wx-config --cxxflags --debug=no --unicode=yes` `pkg-config --cflags gtk+-2.0` -DFFS_LINUX -DTIXML_USE_STL -DZSTRING_CHAR -O3 -pthread -c -LINKFLAGS=`wx-config --libs --debug=no --unicode=yes` -lboost_thread -O3 -pthread +FFS_CPPFLAGS=-Wall -pipe -DNDEBUG -DwxUSE_UNICODE `wx-config --cxxflags --debug=no --unicode=yes --static=yes` `pkg-config --cflags gtk+-2.0` -DFFS_LINUX -DTIXML_USE_STL -O3 -pthread +LINKFLAGS=`wx-config --libs --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a -O3 -pthread #support for GTKMM FFS_CPPFLAGS+=`pkg-config --cflags gtkmm-2.4` @@ -47,7 +47,7 @@ FILE_LIST+=library/db_file.cpp FILE_LIST+=library/dir_lock.cpp FILE_LIST+=shared/localization_no_BOM.cpp FILE_LIST+=shared/file_io.cpp -FILE_LIST+=shared/drag_n_drop.cpp +FILE_LIST+=shared/dir_name.cpp FILE_LIST+=shared/guid.cpp FILE_LIST+=shared/check_exist.cpp FILE_LIST+=shared/tinyxml/tinyxml.cpp @@ -89,10 +89,11 @@ removeBOM: tools/remove_BOM.cpp %.dep : %.cpp #strip path information - g++ $(FFS_CPPFLAGS) $< -o OBJ/$(subst .cpp,.o,$(notdir $<)) + g++ $(FFS_CPPFLAGS) -c $< -o OBJ/$(subst .cpp,.o,$(notdir $<)) FreeFileSync: init removeBOM $(DEP_LIST) - g++ -o BUILD/$(APPNAME) $(OBJECT_LIST) $(LINKFLAGS) +#respect linker order: wxWidgets libraries last + g++ -o ./BUILD/$(APPNAME) $(OBJECT_LIST) $(LINKFLAGS) clean: rm -rf OBJ diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index e423cbfb..701e8c9c 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -27,7 +27,7 @@ <Add library="libwxbase28u.a" /> <Add library="libwxpng.a" /> <Add library="libwxzlib.a" /> - <Add library="libboost_thread-mgw45-mt-s-1_43.a" /> + <Add library="libboost_thread-mgw45-mt-s-1_44.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> </Linker> </Target> @@ -51,7 +51,7 @@ <Add library="libwxbase28ud.a" /> <Add library="libwxpngd.a" /> <Add library="libwxzlibd.a" /> - <Add library="libboost_thread-mgw45-mt-sd-1_43.a" /> + <Add library="libboost_thread-mgw45-mt-sd-1_44.a" /> <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll" /> </Linker> </Target> @@ -68,8 +68,9 @@ <Add option="-D__WXMSW__" /> <Add option="-DwxUSE_UNICODE" /> <Add option="-DFFS_WIN" /> - <Add option="-DZSTRING_WIDE_CHAR" /> <Add option="-DTIXML_USE_STL" /> + <Add option="-DBOOST_THREAD_NO_LIB" /> + <Add option="-DBOOST_THREAD_USE_LIB" /> <Add directory="C:\Programme\C++\wxWidgets\include" /> <Add directory="C:\Program Files\C++\Boost" /> </Compiler> @@ -94,7 +95,6 @@ <Unit filename="WxWizDialog.fbp" /> <Unit filename="application.cpp" /> <Unit filename="application.h" /> - <Unit filename="functions.cpp" /> <Unit filename="functions.h" /> <Unit filename="gui_generated.cpp" /> <Unit filename="gui_generated.h" /> @@ -122,14 +122,16 @@ <Unit filename="xml_proc.h" /> <Unit filename="..\Shared\custom_button.cpp" /> <Unit filename="..\Shared\custom_button.h" /> - <Unit filename="..\Shared\drag_n_drop.cpp" /> - <Unit filename="..\Shared\drag_n_drop.h" /> + <Unit filename="..\Shared\dir_name.cpp" /> + <Unit filename="..\Shared\dir_name.h" /> <Unit filename="..\Shared\zstring.cpp" /> <Unit filename="..\Shared\zstring.h" /> <Unit filename="..\library\process_xml.cpp" /> <Unit filename="..\shared\check_exist.cpp" /> <Unit filename="..\shared\dll_loader.cpp" /> <Unit filename="..\shared\dll_loader.h" /> + <Unit filename="..\shared\dst_hack.cpp" /> + <Unit filename="..\shared\dst_hack.h" /> <Unit filename="..\shared\file_error.h" /> <Unit filename="..\shared\file_handling.cpp" /> <Unit filename="..\shared\file_handling.h" /> diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj index 4812a3d0..858c909b 100644 --- a/RealtimeSync/RealtimeSync.vcxproj +++ b/RealtimeSync/RealtimeSync.vcxproj @@ -99,10 +99,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets\include;C:\Programme\C++\wxWidgets\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)/pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -129,10 +129,10 @@ <PrecompiledHeader>Use</PrecompiledHeader> <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <PrecompiledHeaderFile>$(ProjectDir)/pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <MultiProcessorCompilation>false</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> @@ -162,7 +162,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets\include;C:\Programme\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> @@ -196,10 +196,10 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR</PreprocessorDefinitions> + <PreprocessorDefinitions>wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL</PreprocessorDefinitions> <AdditionalIncludeDirectories>C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> <DisableLanguageExtensions>false</DisableLanguageExtensions> @@ -229,7 +229,8 @@ <ClCompile Include="..\shared\check_exist.cpp" /> <ClCompile Include="..\shared\custom_button.cpp" /> <ClCompile Include="..\shared\dll_loader.cpp" /> - <ClCompile Include="..\shared\drag_n_drop.cpp" /> + <ClCompile Include="..\shared\dir_name.cpp" /> + <ClCompile Include="..\shared\dst_hack.cpp" /> <ClCompile Include="..\shared\file_handling.cpp" /> <ClCompile Include="..\shared\file_io.cpp" /> <ClCompile Include="..\shared\file_traverser.cpp" /> @@ -251,7 +252,6 @@ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)/pch.h</PrecompiledHeaderFile> </ClCompile> - <ClCompile Include="functions.cpp" /> <ClCompile Include="gui_generated.cpp" /> <ClCompile Include="main_dlg.cpp" /> <ClCompile Include="notify.cpp" /> diff --git a/RealtimeSync/functions.cpp b/RealtimeSync/functions.cpp deleted file mode 100644 index f66db6b4..00000000 --- a/RealtimeSync/functions.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#include "functions.h" -#include <wx/textctrl.h> -#include <wx/filepicker.h> -#include "../shared/string_conv.h" -#include "../shared/file_handling.h" - -using namespace ffs3; - -void rts::setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker) -{ - txtCtrl->SetValue(dirname); - const Zstring leftDirFormatted = ffs3::getFormattedDirectoryName(wxToZ(dirname)); - if (dirExists(leftDirFormatted)) - dirPicker->SetPath(zToWx(leftDirFormatted)); -} - diff --git a/RealtimeSync/functions.h b/RealtimeSync/functions.h deleted file mode 100644 index 5b20ee9e..00000000 --- a/RealtimeSync/functions.h +++ /dev/null @@ -1,21 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#ifndef FUNCTIONS_H_INCLUDED -#define FUNCTIONS_H_INCLUDED - -#include <wx/string.h> - -class wxTextCtrl; -class wxDirPickerCtrl; - - -namespace rts -{ -void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); -} - -#endif // FUNCTIONS_H_INCLUDED diff --git a/RealtimeSync/gui_generated.cpp b/RealtimeSync/gui_generated.cpp index 5bdae20e..6b15a5eb 100644 --- a/RealtimeSync/gui_generated.cpp +++ b/RealtimeSync/gui_generated.cpp @@ -152,19 +152,19 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( sbSizer3, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); - m_staticline1 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); - bSizer1->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxBOTTOM, 10 ); - wxStaticBoxSizer* sbSizer4; - sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Delay") ), wxVERTICAL ); + sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Minimum Idle Time") ), wxVERTICAL ); m_spinCtrlDelay = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 2000000000, 0 ); - m_spinCtrlDelay->SetToolTip( _("Delay between detection of changes and execution of command line in seconds") ); + m_spinCtrlDelay->SetToolTip( _("Idle time between detection of last change and execution of command line in seconds") ); sbSizer4->Add( m_spinCtrlDelay, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); bSizer1->Add( sbSizer4, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + m_staticline1 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bSizer1->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxBOTTOM, 10 ); + m_buttonStart = new wxButtonWithImage( m_panelMain, wxID_ANY, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 ); m_buttonStart->SetDefault(); m_buttonStart->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) ); diff --git a/RealtimeSync/gui_generated.h b/RealtimeSync/gui_generated.h index 7be541d4..2b00d1bc 100644 --- a/RealtimeSync/gui_generated.h +++ b/RealtimeSync/gui_generated.h @@ -5,8 +5,8 @@ // PLEASE DO "NOT" EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// -#ifndef __guiGenerated__ -#define __guiGenerated__ +#ifndef __gui_generated__ +#define __gui_generated__ #include <wx/intl.h> @@ -65,8 +65,8 @@ class MainDlgGenerated : public wxFrame wxScrolledWindow* m_scrolledWinFolders; wxBoxSizer* bSizerFolders; wxTextCtrl* m_textCtrlCommand; - wxStaticLine* m_staticline1; wxSpinCtrl* m_spinCtrlDelay; + wxStaticLine* m_staticline1; wxButtonWithImage* m_buttonStart; wxButton* m_buttonCancel; @@ -107,4 +107,4 @@ class FolderGenerated : public wxPanel }; -#endif //__guiGenerated__ +#endif //__gui_generated__ diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp index d1a30c48..447f1f01 100644 --- a/RealtimeSync/main_dlg.cpp +++ b/RealtimeSync/main_dlg.cpp @@ -8,7 +8,7 @@ #include "resources.h" #include "../shared/custom_button.h" #include "../shared/standard_paths.h" -#include "functions.h" +//#include "functions.h" #include <wx/msgdlg.h> #include <wx/wupdlock.h> #include "watcher.h" @@ -43,7 +43,7 @@ MainDialog::MainDialog(wxDialog *dlg, Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(MainDialog::OnKeyPressed), NULL, this); //prepare drag & drop - dragDropOnFolder.reset(new ffs3::DragDropOnDlg(m_panelMainFolder, m_dirPickerMain, m_txtCtrlDirectoryMain)); + dirNameFirst.reset(new ffs3::DirectoryName(m_panelMainFolder, m_dirPickerMain, m_txtCtrlDirectoryMain)); //load config values xmlAccess::XmlRealConfig newConfig; @@ -141,7 +141,7 @@ void MainDialog::OnShowHelp(wxCommandEvent& event) void MainDialog::OnMenuAbout(wxCommandEvent& event) { - //build information + //build information wxString build = __TDATE__; #if wxUSE_UNICODE build += wxT(" - Unicode"); @@ -156,8 +156,8 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event) build += wxT(" x86"); assert_static(util::is32BitBuild || util::is64BitBuild); -wxString buildFormatted = _("(Build: %x)"); -buildFormatted.Replace(wxT("%x"), build); + wxString buildFormatted = _("(Build: %x)"); + buildFormatted.Replace(wxT("%x"), build); wxMessageDialog* aboutDlg = new wxMessageDialog(this, wxString(wxT("RealtimeSync")) + wxT("\n\n") + buildFormatted, _("About"), wxOK); aboutDlg->ShowModal(); @@ -270,19 +270,14 @@ void MainDialog::OnLoadConfig(wxCommandEvent& event) void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg) { //clear existing folders - m_txtCtrlDirectoryMain->ChangeValue(wxEmptyString); - m_dirPickerMain->SetPath(wxEmptyString); + dirNameFirst->setName(Zstring()); clearAddFolders(); if (!cfg.directories.empty()) { //fill top folder - m_txtCtrlDirectoryMain->SetValue(*cfg.directories.begin()); - - const Zstring dirFormatted = ffs3::getFormattedDirectoryName(wxToZ(*cfg.directories.begin())); - if (dirExists(dirFormatted)) - m_dirPickerMain->SetPath(zToWx(dirFormatted)); + dirNameFirst->setName(wxToZ(*cfg.directories.begin())); //fill additional folders addFolder(std::vector<wxString>(cfg.directories.begin() + 1, cfg.directories.end())); @@ -300,9 +295,9 @@ xmlAccess::XmlRealConfig MainDialog::getConfiguration() { xmlAccess::XmlRealConfig output; - output.directories.push_back(m_txtCtrlDirectoryMain->GetValue()); - for (std::vector<FolderPanel*>::const_iterator i = additionalFolders.begin(); i != additionalFolders.end(); ++i) - output.directories.push_back((*i)->m_txtCtrlDirectory->GetValue()); + output.directories.push_back(zToWx(dirNameFirst->getName())); + for (std::vector<DirectoryPanel*>::const_iterator i = dirNamesExtra.begin(); i != dirNamesExtra.end(); ++i) + output.directories.push_back(zToWx((*i)->getName())); output.commandline = m_textCtrlCommand->GetValue(); output.delay = m_spinCtrlDelay->GetValue();; @@ -313,13 +308,13 @@ xmlAccess::XmlRealConfig MainDialog::getConfiguration() void MainDialog::OnAddFolder(wxCommandEvent& event) { - const wxString topFolder = m_txtCtrlDirectoryMain->GetValue(); + const wxString topFolder = zToWx(dirNameFirst->getName()); //clear existing top folder first - rts::setDirectoryName(wxEmptyString, m_txtCtrlDirectoryMain, m_dirPickerMain); + dirNameFirst->setName(Zstring()); std::vector<wxString> newFolders; - newFolders.push_back(topFolder.c_str()); + newFolders.push_back(topFolder); addFolder(newFolders, true); //add pair in front of additonal pairs } @@ -329,11 +324,11 @@ void MainDialog::OnRemoveFolder(wxCommandEvent& event) { //find folder pair originating the event const wxObject* const eventObj = event.GetEventObject(); - for (std::vector<FolderPanel*>::const_iterator i = additionalFolders.begin(); i != additionalFolders.end(); ++i) + for (std::vector<DirectoryPanel*>::const_iterator i = dirNamesExtra.begin(); i != dirNamesExtra.end(); ++i) { if (eventObj == static_cast<wxObject*>((*i)->m_bpButtonRemoveFolder)) { - removeAddFolder(i - additionalFolders.begin()); + removeAddFolder(i - dirNamesExtra.begin()); return; } } @@ -342,10 +337,11 @@ void MainDialog::OnRemoveFolder(wxCommandEvent& event) void MainDialog::OnRemoveTopFolder(wxCommandEvent& event) { - if (additionalFolders.size() > 0) + if (dirNamesExtra.size() > 0) { - const wxString topDir = (*additionalFolders.begin())->m_txtCtrlDirectory->GetValue().c_str(); - rts::setDirectoryName(topDir, m_txtCtrlDirectoryMain, m_dirPickerMain); + const wxString topDir = (*dirNamesExtra.begin())->getName().c_str(); + + dirNameFirst->setName(wxToZ(topDir)); removeAddFolder(0); //remove first of additional folders } @@ -370,7 +366,7 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron for (std::vector<wxString>::const_iterator i = newFolders.begin(); i != newFolders.end(); ++i) { //add new folder pair - FolderPanel* newFolder = new FolderPanel(m_scrolledWinFolders); + DirectoryPanel* newFolder = new DirectoryPanel(m_scrolledWinFolders); newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); //get size of scrolled window @@ -379,23 +375,23 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron if (addFront) { bSizerFolders->Insert(0, newFolder, 0, wxEXPAND, 5); - additionalFolders.insert(additionalFolders.begin(), newFolder); + dirNamesExtra.insert(dirNamesExtra.begin(), newFolder); } else { bSizerFolders->Add(newFolder, 0, wxEXPAND, 5); - additionalFolders.push_back(newFolder); + dirNamesExtra.push_back(newFolder); } //register events newFolder->m_bpButtonRemoveFolder->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainDialog::OnRemoveFolder), NULL, this ); //insert directory name - rts::setDirectoryName(*i, newFolder->m_txtCtrlDirectory, newFolder->m_dirPicker); + newFolder->setName(wxToZ(*i)); } //set size of scrolled window - const size_t additionalRows = std::min(additionalFolders.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown + const size_t additionalRows = std::min(dirNamesExtra.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown m_scrolledWinFolders->SetMinSize(wxSize( -1, folderHeight * static_cast<int>(additionalRows))); //adapt delete top folder pair button @@ -414,23 +410,23 @@ void MainDialog::removeAddFolder(const int pos) { wxWindowUpdateLocker dummy(this); //avoid display distortion - if (0 <= pos && pos < int(additionalFolders.size())) + if (0 <= pos && pos < int(dirNamesExtra.size())) { //remove folder pairs from window - FolderPanel* dirToDelete = additionalFolders[pos]; + DirectoryPanel* dirToDelete = dirNamesExtra[pos]; const int folderHeight = dirToDelete->GetSize().GetHeight(); bSizerFolders->Detach(dirToDelete); //Remove() does not work on Window*, so do it manually dirToDelete->Destroy(); // - additionalFolders.erase(additionalFolders.begin() + pos); //remove last element in vector + dirNamesExtra.erase(dirNamesExtra.begin() + pos); //remove last element in vector //set size of scrolled window - const size_t additionalRows = std::min(additionalFolders.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown + const size_t additionalRows = std::min(dirNamesExtra.size(), MAX_ADD_FOLDERS); //up to MAX_ADD_FOLDERS additional folders shall be shown m_scrolledWinFolders->SetMinSize(wxSize( -1, folderHeight * static_cast<int>(additionalRows))); //adapt delete top folder pair button - if (additionalFolders.size() == 0) + if (dirNamesExtra.size() == 0) { m_bpButtonRemoveTopFolder->Hide(); m_panelMainFolder->Layout(); @@ -448,7 +444,7 @@ void MainDialog::clearAddFolders() { wxWindowUpdateLocker dummy(this); //avoid display distortion - additionalFolders.clear(); + dirNamesExtra.clear(); bSizerFolders->Clear(true); m_bpButtonRemoveTopFolder->Hide(); diff --git a/RealtimeSync/main_dlg.h b/RealtimeSync/main_dlg.h index 0f408f6d..22c39146 100644 --- a/RealtimeSync/main_dlg.h +++ b/RealtimeSync/main_dlg.h @@ -10,7 +10,7 @@ #include "gui_generated.h" #include <vector> #include <memory> -#include "../shared/drag_n_drop.h" +#include "../shared/dir_name.h" namespace xmlAccess { @@ -18,16 +18,25 @@ struct XmlRealConfig; } -class FolderPanel : public FolderGenerated +class DirectoryPanel : public FolderGenerated { public: - FolderPanel(wxWindow* parent) : + DirectoryPanel(wxWindow* parent) : FolderGenerated(parent), - dragDropOnFolder(new ffs3::DragDropOnDlg(this, m_dirPicker, m_txtCtrlDirectory)) {} + dirName(this, m_dirPicker, m_txtCtrlDirectory) {} + + void setName(const Zstring& dirname) + { + dirName.setName(dirname); + } + + Zstring getName() const + { + return dirName.getName(); + } private: - //support for drag and drop - std::auto_ptr<ffs3::DragDropOnDlg> dragDropOnFolder; + ffs3::DirectoryName dirName; }; @@ -65,11 +74,8 @@ private: static const wxString& lastConfigFileName(); - //additional folders - std::vector<FolderPanel*> additionalFolders; //additional pairs to the standard pair - - //support for drag and drop on main folder - std::auto_ptr<ffs3::DragDropOnDlg> dragDropOnFolder; + std::auto_ptr<ffs3::DirectoryName> dirNameFirst; + std::vector<DirectoryPanel*> dirNamesExtra; //additional pairs to the standard pair }; #endif // REALTIMESYNCMAIN_H diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile index 764cb5f9..cf7aca36 100644 --- a/RealtimeSync/makefile +++ b/RealtimeSync/makefile @@ -3,12 +3,11 @@ APPNAME = RealtimeSync prefix = /usr BINDIR = $(DESTDIR)$(prefix)/bin -FFS_CPPFLAGS=-Wall -pipe -DNDEBUG -DwxUSE_UNICODE `wx-config --cxxflags --debug=no --unicode=yes` `pkg-config --cflags gtk+-2.0` -DFFS_LINUX -DTIXML_USE_STL -DZSTRING_CHAR -O3 -pthread -c -LINKFLAGS=`wx-config --libs --debug=no --unicode=yes` -lboost_thread -O3 -pthread +FFS_CPPFLAGS=-Wall -pipe -DNDEBUG -DwxUSE_UNICODE `wx-config --cxxflags --debug=no --unicode=yes --static=yes` `pkg-config --cflags gtk+-2.0` -DFFS_LINUX -DTIXML_USE_STL -O3 -pthread +LINKFLAGS=`wx-config --libs --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a -O3 -pthread FILE_LIST= #internal list of all *.cpp files needed for compilation FILE_LIST+=application.cpp -FILE_LIST+=functions.cpp FILE_LIST+=gui_generated.cpp FILE_LIST+=main_dlg.cpp FILE_LIST+=resources.cpp @@ -26,7 +25,7 @@ FILE_LIST+=../shared/tinyxml/tinyxmlerror.cpp FILE_LIST+=../shared/tinyxml/tinyxmlparser.cpp FILE_LIST+=../shared/global_func.cpp FILE_LIST+=../shared/system_func.cpp -FILE_LIST+=../shared/drag_n_drop.cpp +FILE_LIST+=../shared/dir_name.cpp FILE_LIST+=../shared/zstring.cpp FILE_LIST+=../shared/xml_base.cpp FILE_LIST+=../shared/custom_button.cpp @@ -55,10 +54,11 @@ removeBOM: ../tools/remove_BOM.cpp %.dep : %.cpp #strip path information - g++ $(FFS_CPPFLAGS) $< -o OBJ/$(subst .cpp,.o,$(notdir $<)) + g++ $(FFS_CPPFLAGS) -c $< -o OBJ/$(subst .cpp,.o,$(notdir $<)) RealtimeSync: init removeBOM $(DEP_LIST) - g++ $(LINKFLAGS) -o ../BUILD/$(APPNAME) $(OBJECT_LIST) +#respect linker order: wxWidgets libraries last + g++ -o ../BUILD/$(APPNAME) $(OBJECT_LIST) $(LINKFLAGS) clean: rm -rf OBJ diff --git a/RealtimeSync/notify.cpp b/RealtimeSync/notify.cpp index fc9ac8cc..599259e6 100644 --- a/RealtimeSync/notify.cpp +++ b/RealtimeSync/notify.cpp @@ -196,9 +196,13 @@ public: &filter, //__in LPVOID NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags if (hNotfication == NULL) - throw ffs3::FileError(wxString(wxT("Could not register device removal notifications:")) + wxT("\n\n") + ffs3::getLastErrorFormatted()); - - notifications.insert(hNotfication); + { + const DWORD lastError = ::GetLastError(); + if (lastError != ERROR_CALL_NOT_IMPLEMENTED) //fail on SAMBA share: this shouldn't be a showstopper! + throw ffs3::FileError(wxString(wxT("Could not register device removal notifications:")) + wxT("\n\n") + ffs3::getLastErrorFormatted(lastError)); + } + else + notifications.insert(hNotfication); } } catch (...) diff --git a/RealtimeSync/resource.rc b/RealtimeSync/resource.rc index 1b70fa6a..f3dfb090 100644 --- a/RealtimeSync/resource.rc +++ b/RealtimeSync/resource.rc @@ -1,24 +1,26 @@ #define IDR_VERSION1 1 +#include "Winver.h" #include "wx/msw/wx.rc" #include "../version/version.rc" A_PROGRAM_ICON ICON DISCARDABLE "RealtimeSync.ico" -IDR_VERSION1 VERSIONINFO -FILEVERSION VER_FREEFILESYNC +IDR_VERSION1 VERSIONINFO +FILEVERSION VER_FREEFILESYNC PRODUCTVERSION VER_FREEFILESYNC -FILEOS 0x00000004 -FILETYPE 0x00000001 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "FFFF04B0" BEGIN - VALUE "ProductVersion", VER_FREEFILESYNC_STR VALUE "FileDescription", "Realtime Application Launcher\0" - VALUE "LegalCopyright", "(c) 2008 - 2010 ZenJu\0" - VALUE "ProductName", "RealtimeSync\0" + VALUE "FileVersion", VER_FREEFILESYNC_STR + VALUE "ProductName", "RealtimeSync\0" + VALUE "ProductVersion", VER_FREEFILESYNC_STR + VALUE "LegalCopyright", "(c) 2008 - 2010 ZenJu\0" END END BLOCK "VarFileInfo" diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp index 1ea7416c..9c0db35a 100644 --- a/RealtimeSync/tray_menu.cpp +++ b/RealtimeSync/tray_menu.cpp @@ -21,18 +21,18 @@ #include "../shared/build_info.h" #include <wx/icon.h> //Linux needs this #include <wx/timer.h> +#include <limits> using namespace rts; -class WaitCallbackImpl : private wxEvtHandler, public rts::WaitCallback //keep this order: else VC++ generates wrong code +class TrayIconHolder : private wxEvtHandler { public: - WaitCallbackImpl(); - ~WaitCallbackImpl(); - - virtual void requestUiRefresh(); + TrayIconHolder(); + ~TrayIconHolder(); + void doUiRefreshNow(); void showIconActive(); void showIconWaiting(); @@ -65,10 +65,10 @@ private: //RtsTrayIcon shall be a dumb class whose sole purpose is to enable wxWidgets deferred deletion -class WaitCallbackImpl::RtsTrayIcon : public wxTaskBarIcon +class TrayIconHolder::RtsTrayIcon : public wxTaskBarIcon { public: - RtsTrayIcon(WaitCallbackImpl* parent) : parent_(parent) {} + RtsTrayIcon(TrayIconHolder* parent) : parent_(parent) {} void parentHasDied() //call before tray icon is marked for deferred deletion { @@ -87,12 +87,12 @@ private: contextMenu->AppendSeparator(); contextMenu->Append(CONTEXT_ABORT, _("&Exit")); //event handling - contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WaitCallbackImpl::OnContextMenuSelection), NULL, parent_); + contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TrayIconHolder::OnContextMenuSelection), NULL, parent_); return contextMenu; //ownership transferred to caller } - WaitCallbackImpl* parent_; + TrayIconHolder* parent_; }; //############################################################################################################## @@ -113,7 +113,7 @@ private: //############################################################################################################## -WaitCallbackImpl::WaitCallbackImpl() : +TrayIconHolder::TrayIconHolder() : m_abortRequested(false), m_resumeRequested(false) { @@ -122,13 +122,13 @@ WaitCallbackImpl::WaitCallbackImpl() : showIconActive(); //register double-click - trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this); + trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), NULL, this); } -WaitCallbackImpl::~WaitCallbackImpl() +TrayIconHolder::~TrayIconHolder() { - trayMenu->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this); + trayMenu->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), NULL, this); trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place trayMenu->parentHasDied(); @@ -138,7 +138,7 @@ WaitCallbackImpl::~WaitCallbackImpl() } -void WaitCallbackImpl::showIconActive() +void TrayIconHolder::showIconActive() { wxIcon realtimeIcon; #ifdef FFS_WIN @@ -150,7 +150,7 @@ void WaitCallbackImpl::showIconActive() } -void WaitCallbackImpl::showIconWaiting() +void TrayIconHolder::showIconWaiting() { wxIcon realtimeIcon; #ifdef FFS_WIN @@ -162,7 +162,7 @@ void WaitCallbackImpl::showIconWaiting() } -void WaitCallbackImpl::OnContextMenuSelection(wxCommandEvent& event) +void TrayIconHolder::OnContextMenuSelection(wxCommandEvent& event) { const int eventId = event.GetId(); switch (static_cast<Selection>(eventId)) @@ -201,10 +201,9 @@ void WaitCallbackImpl::OnContextMenuSelection(wxCommandEvent& event) } -void WaitCallbackImpl::requestUiRefresh() +void TrayIconHolder::doUiRefreshNow() { - if (updateUiIsAllowed()) - wxTheApp->Yield(); + wxTheApp->Yield(); if (m_abortRequested) throw ::AbortThisProcess(QUIT); @@ -226,6 +225,60 @@ std::vector<Zstring> convert(const std::vector<wxString>& dirList) } +class StartSyncNowException {}; + + +class WaitCallbackImpl : public rts::WaitCallback +{ +public: + WaitCallbackImpl() : nextSyncStart_(std::numeric_limits<long>::max()) {} + + void notifyAllDirectoriesExist() + { + trayIcon.showIconActive(); + } + + void notifyDirectoryMissing() + { + trayIcon.showIconWaiting(); + } + + virtual void requestUiRefresh() //throw StartSyncNowException() + { + if (nextSyncStart_ <= wxGetLocalTime()) + throw StartSyncNowException(); //abort wait and start sync + + if (updateUiIsAllowed()) + trayIcon.doUiRefreshNow(); + } + + void scheduleNextSync(long nextSyncStart) + { + nextSyncStart_ = nextSyncStart; + } + +private: + TrayIconHolder trayIcon; + long nextSyncStart_; +}; + +/* +Data Flow: +---------- + +TrayIconHolder (GUI output) + /|\ + | +WaitCallbackImpl (higher level "interface") + /|\ + | +startDirectoryMonitor() (wire dir-changes and execution of commandline) + /|\ + | +watcher.h (low level wait for directory changes) +*/ + + rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config) { const std::vector<Zstring> dirList = convert(config.directories); @@ -237,35 +290,38 @@ rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& if (config.commandline.empty()) throw ffs3::FileError(_("Command line is empty!")); + callback.notifyDirectoryMissing(); + waitForMissingDirs(dirList, &callback); + callback.notifyAllDirectoriesExist(); + while (true) { - //execute commandline - callback.showIconWaiting(); - waitForMissingDirs(dirList, &callback); - callback.showIconActive(); - wxExecute(config.commandline, wxEXEC_SYNC); //execute command wxLog::FlushActive(); //show wxWidgets error messages (if any) - //wait for changes (and for all directories to become available) - switch (waitForChanges(dirList, &callback)) - { - case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available! - callback.showIconWaiting(); - waitForMissingDirs(dirList, &callback); - callback.showIconActive(); - break; - case CHANGE_DETECTED: - break; - } + callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet) - //some delay - const long nextExec = wxGetLocalTime() + static_cast<long>(config.delay); - while (wxGetLocalTime() < nextExec) + try { - callback.requestUiRefresh(); - wxMilliSleep(rts::UI_UPDATE_INTERVAL); + while (true) + { + //wait for changes (and for all directories to become available) + switch (waitForChanges(dirList, &callback)) + { + case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available! + callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet) + callback.notifyDirectoryMissing(); + waitForMissingDirs(dirList, &callback); + callback.notifyAllDirectoriesExist(); + break; + case CHANGE_DETECTED: + break; + } + + callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay)); + } } + catch (StartSyncNowException) {} } } catch (const ::AbortThisProcess& ab) diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 89fc5e61..cf2791ad 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -59,9 +59,9 @@ class DirsOnlyTraverser : public ffs3::TraverseCallback public: DirsOnlyTraverser(std::vector<std::string>& dirs) : m_dirs(dirs) {} - virtual void onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) {} - virtual void onSymlink(const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details) {} - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {} + virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) {} + virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName) { m_dirs.push_back(fullName.c_str()); return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), this); diff --git a/RealtimeSync/xml_ffs.cpp b/RealtimeSync/xml_ffs.cpp index 3f87b20f..864ceff9 100644 --- a/RealtimeSync/xml_ffs.cpp +++ b/RealtimeSync/xml_ffs.cpp @@ -8,7 +8,7 @@ #include "../shared/standard_paths.h" #include "../shared/global_func.h" #include "../shared/zstring.h" -#include "functions.h" +//#include "functions.h" #include "../shared/xml_base.h" #include "../shared/string_conv.h" diff --git a/RealtimeSync/xml_proc.h b/RealtimeSync/xml_proc.h index bac42f1e..3e6c0c0a 100644 --- a/RealtimeSync/xml_proc.h +++ b/RealtimeSync/xml_proc.h @@ -16,7 +16,7 @@ namespace xmlAccess { struct XmlRealConfig { - XmlRealConfig() : delay(5) {} + XmlRealConfig() : delay(10) {} std::vector<wxString> directories; wxString commandline; size_t delay; diff --git a/algorithm.cpp b/algorithm.cpp index 128742ed..5e6b2b66 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -100,7 +100,7 @@ private: break; case SYMLINK_CONFLICT: linkObj.setSyncDir(config.conflict); - break; + break; case SYMLINK_DIFFERENT: linkObj.setSyncDir(config.different); break; @@ -572,6 +572,7 @@ private: { return loadFromDisk(baseDirectory); } + catch (FileErrorDatabaseNotExisting&) {} //let's ignore these errors for now... catch (FileError& error) //e.g. incompatible database version { if (handler_) handler_->reportWarning(error.msg() + wxT(" \n\n") + @@ -948,7 +949,7 @@ void ffs3::setSyncDirectionRec(SyncDirection newDirection, FileSystemObject& fsO { SetNewDirection(newDirection_).execute(const_cast<DirMapping&>(dirObj)); //phyiscal object is not const in this method anyway } -private: + private: const SyncDirection newDirection_; } recurse(newDirection); fsObj.accept(recurse); @@ -1022,7 +1023,7 @@ void ffs3::setActiveStatus(bool newStatus, ffs3::FileSystemObject& fsObj) else InOrExcludeAllRows<false>().execute(const_cast<DirMapping&>(dirObj)); // } -private: + private: const bool newStatus_; } recurse(newStatus); fsObj.accept(recurse); @@ -1110,7 +1111,7 @@ bool FilterData<STRATEGY_ACTIVE_ONLY>::processObject(ffs3::FileSystemObject& fsO void ffs3::addExcludeFiltering(const Zstring& excludeFilter, FolderComparison& folderCmp) { for (std::vector<BaseDirMapping>::iterator i = folderCmp.begin(); i != folderCmp.end(); ++i) - FilterData<STRATEGY_ACTIVE_ONLY>(*BaseFilter::FilterRef(new NameFilter(DefaultStr("*"), excludeFilter))).execute(*i); + FilterData<STRATEGY_ACTIVE_ONLY>(*BaseFilter::FilterRef(new NameFilter(Zstr("*"), excludeFilter))).execute(*i); } @@ -1207,10 +1208,26 @@ std::pair<wxString, int> ffs3::deleteFromGridAndHDPreview( //assemble message co } +namespace +{ +struct RemoveCallbackImpl : public ffs3::RemoveDirCallback +{ + RemoveCallbackImpl(DeleteFilesHandler& deleteCallback) : deleteCallback_(deleteCallback) {} + + virtual void requestUiRefresh(const Zstring& currentObject) + { + deleteCallback_.deletionSuccessful(0); + } + +private: + DeleteFilesHandler& deleteCallback_; +}; +} + template <SelectedSide side> void deleteFromGridAndHDOneSide(std::vector<FileSystemObject*>& rowsToDeleteOneSide, const bool useRecycleBin, - DeleteFilesHandler* statusHandler) + DeleteFilesHandler& statusHandler) { for (std::vector<FileSystemObject*>::const_iterator i = rowsToDeleteOneSide.begin(); i != rowsToDeleteOneSide.end(); ++i) { @@ -1225,9 +1242,13 @@ void deleteFromGridAndHDOneSide(std::vector<FileSystemObject*>& rowsToDeleteOneS ffs3::moveToRecycleBin(fsObj->getFullName<side>()); //throw (FileError) else { + RemoveCallbackImpl removeCallback(statusHandler); + //del directories and symlinks struct DeletePermanently : public FSObjectVisitor { + DeletePermanently(RemoveCallbackImpl* remCallback) : remCallback_(remCallback) {} + virtual void visit(const FileMapping& fileObj) { ffs3::removeFile(fileObj.getFullName<side>()); @@ -1238,7 +1259,7 @@ void deleteFromGridAndHDOneSide(std::vector<FileSystemObject*>& rowsToDeleteOneS switch (linkObj.getLinkType<side>()) { case LinkDescriptor::TYPE_DIR: - ffs3::removeDirectory(linkObj.getFullName<side>()); + ffs3::removeDirectory(linkObj.getFullName<side>(), NULL); break; case LinkDescriptor::TYPE_FILE: ffs3::removeFile(linkObj.getFullName<side>()); @@ -1248,21 +1269,24 @@ void deleteFromGridAndHDOneSide(std::vector<FileSystemObject*>& rowsToDeleteOneS virtual void visit(const DirMapping& dirObj) { - ffs3::removeDirectory(dirObj.getFullName<side>()); + ffs3::removeDirectory(dirObj.getFullName<side>(), remCallback_); } - } delPerm; + + private: + RemoveCallbackImpl* remCallback_; + } delPerm(&removeCallback); fsObj->accept(delPerm); } fsObj->removeObject<side>(); //if directory: removes recursively! } - statusHandler->deletionSuccessful(); //notify successful file/folder deletion + statusHandler.deletionSuccessful(1); //notify successful file/folder deletion break; } catch (const FileError& error) { - DeleteFilesHandler::Response rv = statusHandler->reportError(error.msg()); + DeleteFilesHandler::Response rv = statusHandler.reportError(error.msg()); if (rv == DeleteFilesHandler::IGNORE_ERROR) break; @@ -1297,12 +1321,12 @@ private: void ffs3::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, - const bool useRecycleBin, - const MainConfiguration& mainConfig, - DeleteFilesHandler* statusHandler) + 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, + const bool useRecycleBin, + const MainConfiguration& mainConfig, + DeleteFilesHandler& statusHandler) { if (folderCmp.size() == 0) return; diff --git a/algorithm.h b/algorithm.h index 7b96358d..7280ed7d 100644 --- a/algorithm.h +++ b/algorithm.h @@ -56,7 +56,7 @@ public: virtual Response reportError(const wxString& errorMessage) = 0; //virtual void totalFilesToDelete(int objectsTotal) = 0; //informs about the total number of files to be deleted - virtual void deletionSuccessful() = 0; //called for each file/folder that has been deleted + virtual void deletionSuccessful(size_t deletedItems) = 0; //called for each file/folder that has been deleted }; void deleteFromGridAndHD(FolderComparison& folderCmp, //attention: rows will be physically deleted! @@ -65,7 +65,7 @@ void deleteFromGridAndHD(FolderComparison& folderCmp, //a const bool deleteOnBothSides, const bool useRecycleBin, const MainConfiguration& mainConfig, - DeleteFilesHandler* statusHandler); + DeleteFilesHandler& statusHandler); } #endif // ALGORITHM_H_INCLUDED diff --git a/comparison.cpp b/comparison.cpp index a049c57a..9071664a 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -25,9 +25,13 @@ #include "library/binary.h" #include "library/dir_lock.h" +#ifdef FFS_WIN +#include "shared/perf.h" +#endif + using namespace ffs3; -const Zstring LOCK_FILE_ENDING = DefaultStr("ffs_lock"); +const Zstring LOCK_FILE_ENDING = Zstr("ffs_lock"); std::vector<ffs3::FolderPairCfg> ffs3::extractCompareCfg(const MainConfiguration& mainCfg) @@ -76,9 +80,9 @@ public: virtual ~DirCallback() {} - virtual void onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details); - virtual void onSymlink(const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details); - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName); + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details); + virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details); + virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName); virtual void onError(const wxString& errorText); private: @@ -103,7 +107,7 @@ public: textScanning(wxToZ(wxString(_("Scanning:")) + wxT(" \n"))), filterInstance(filter) {} - virtual void onFile(const DefaultChar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details); + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details); private: typedef boost::shared_ptr<const DirCallback> CallbackPointer; @@ -116,17 +120,17 @@ private: }; -void DirCallback::onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) +void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) { //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"") Zstring statusText = baseCallback_->textScanning; statusText.reserve(statusText.length() + fullName.length() + 2); - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); statusText += fullName; - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); //update UI/commandline status information - statusHandler->updateStatusText(statusText); + statusHandler->reportInfo(statusText); //------------------------------------------------------------------------------------ //apply filter before processing (use relative name!) @@ -155,7 +159,7 @@ void DirCallback::onFile(const DefaultChar* shortName, const Zstring& fullName, } -void DirCallback::onSymlink(const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details) +void DirCallback::onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { if (baseCallback_->handleSymlinks_ == SYMLINK_IGNORE) return; @@ -163,12 +167,12 @@ void DirCallback::onSymlink(const DefaultChar* shortName, const Zstring& fullNam //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"") Zstring statusText = baseCallback_->textScanning; statusText.reserve(statusText.length() + fullName.length() + 2); - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); statusText += fullName; - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); //update UI/commandline status information - statusHandler->updateStatusText(statusText); + statusHandler->reportInfo(statusText); //------------------------------------------------------------------------------------ const Zstring& relName = relNameParentPf_ + shortName; @@ -189,19 +193,19 @@ void DirCallback::onSymlink(const DefaultChar* shortName, const Zstring& fullNam } -TraverseCallback::ReturnValDir DirCallback::onDir(const DefaultChar* shortName, const Zstring& fullName) +TraverseCallback::ReturnValDir DirCallback::onDir(const Zchar* shortName, const Zstring& fullName) { using common::FILE_NAME_SEPARATOR; //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"") Zstring statusText = baseCallback_->textScanning; statusText.reserve(statusText.length() + fullName.length() + 2); - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); statusText += fullName; - statusText += DefaultChar('\"'); + statusText += Zchar('\"'); //update UI/commandline status information - statusHandler->updateStatusText(statusText); + statusHandler->reportInfo(statusText); //------------------------------------------------------------------------------------ const Zstring& relName = relNameParentPf_ + shortName; @@ -226,7 +230,7 @@ TraverseCallback::ReturnValDir DirCallback::onDir(const DefaultChar* shortName, DirCallback* subDirCallback = new DirCallback(baseCallback_, relName + FILE_NAME_SEPARATOR, subDir, statusHandler); baseCallback_->callBackBox.push_back(BaseDirCallback::CallbackPointer(subDirCallback)); //handle ownership //attention: ensure directory filtering is applied later to exclude actually filtered directories - return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), subDirCallback); + return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), *subDirCallback); } @@ -245,14 +249,18 @@ void DirCallback::onError(const wxString& errorText) } -void BaseDirCallback::onFile(const DefaultChar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details) +void BaseDirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details) { //do not list the database file(s) sync.ffs_db, sync.x64.ffs_db, etc. or lock files - const Zstring& ending = Zstring(shortName).AfterLast(DefaultChar('.')); //(returns the whole string if ch not found) - - if ( cmpFileName(ending, SYNC_DB_FILE_ENDING) == 0 || - cmpFileName(ending, LOCK_FILE_ENDING) == 0) - return; + const Zstring fileName(shortName); + const size_t pos = fileName.rfind(Zchar('.')); + if (pos != Zstring::npos) + { + const Zstring ending(shortName + pos + 1); //(returns the whole string if ch not found) + if ( EqualFilename()(ending, SYNC_DB_FILE_ENDING) || + EqualFilename()(ending, LOCK_FILE_ENDING)) + return; + } DirCallback::onFile(shortName, fullName, details); } @@ -273,9 +281,8 @@ struct DirBufferKey bool operator<(const DirBufferKey& b) const { - const int rv = cmpFileName(directoryName, b.directoryName); - if (rv != 0) - return rv < 0; + if (!EqualFilename()(directoryName, b.directoryName)) + return LessFilename()(directoryName, b.directoryName); return *filter < *b.filter; } @@ -306,6 +313,30 @@ private: }; //------------------------------------------------------------------------------------------ + +#ifdef FFS_WIN +class DstHackCallbackImpl : public DstHackCallback +{ +public: + DstHackCallbackImpl(StatusHandler& statusUpdater) : + textApplyingDstHack(wxToZ(_("Encode extended time information: %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""))), + statusUpdater_(statusUpdater) {} + +private: + virtual void requestUiRefresh(const Zstring& filename) //applying DST hack imposes significant one-time performance drawback => callback to inform user + { + Zstring statusText = textApplyingDstHack; + statusText.Replace(Zstr("%x"), filename); + statusUpdater_.reportInfo(statusText); + statusUpdater_.requestUiRefresh(); + } + + const Zstring textApplyingDstHack; + StatusHandler& statusUpdater_; +}; +#endif + + DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferKey& newKey) { DirBufferValue baseContainer(new DirContainer); @@ -332,8 +363,13 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK break; } + std::auto_ptr<ffs3::DstHackCallback> dstCallback; +#ifdef FFS_WIN + dstCallback.reset(new DstHackCallbackImpl(*statusUpdater_)); +#endif + //get all files and folders from directoryPostfixed (and subdirectories) - traverseFolder(newKey.directoryName, followSymlinks, &traverser); //exceptions may be thrown! + traverseFolder(newKey.directoryName, followSymlinks, traverser, dstCallback.get()); //exceptions may be thrown! } return *baseContainer.get(); } @@ -420,7 +456,7 @@ bool dependencyExists(const std::set<Zstring>& folders, const Zstring& newFolder for (std::set<Zstring>::const_iterator i = folders.begin(); i != folders.end(); ++i) { const size_t commonLen = std::min(newFolder.length(), i->length()); - if (cmpFileName(Zstring(newFolder.c_str(), commonLen), Zstring(i->c_str(), commonLen)) == 0) //test wheter i begins with newFolder or the other way round + if (EqualFilename()(Zstring(newFolder.c_str(), commonLen), Zstring(i->c_str(), commonLen))) //test wheter i begins with newFolder or the other way round { warningMessage = wxString(_("Directories are dependent! Be careful when setting up synchronization rules:")) + wxT("\n") + wxT("\"") + zToWx(*i) + wxT("\"\n") + @@ -529,6 +565,7 @@ std::set<Zstring> getFolders(const std::vector<FolderPairCfg>& directoryPairsFor output.insert(i->leftDirectory); output.insert(i->rightDirectory); } + output.erase(Zstring()); //remove empty directory strings return output; } @@ -574,19 +611,16 @@ void formatPair(FolderPairCfg& input) } } - //############################################################################################################################# CompareProcess::CompareProcess(SymLinkHandling handleSymlinks, size_t fileTimeTol, - bool ignoreOneHourDiff, xmlAccess::OptionalDialogs& warnings, StatusHandler* handler) : fileTimeTolerance(fileTimeTol), - ignoreOneHourDifference(ignoreOneHourDiff), m_warnings(warnings), statusUpdater(handler), - txtComparingContentOfFiles(wxToZ(_("Comparing content of files %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)) + txtComparingContentOfFiles(wxToZ(_("Comparing content of files %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false)) { directoryBuffer.reset(new DirectoryBuffer(handleSymlinks, handler)); } @@ -600,7 +634,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc wxLogNull noWxLogs; //hide wxWidgets log messages in release build #endif - //PERF_START; +// #ifdef FFS_WIN +// PERF_START; +// #endif //init process: keep at beginning so that all gui elements are initialized properly statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects @@ -628,35 +664,36 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc { //place a lock on all directories before traversing (sync.ffs_lock) std::map<Zstring, DirLock> lockHolder; - - const std::set<Zstring> folderList = getFolders(directoryPairsFormatted); - for (std::set<Zstring>::const_iterator i = folderList.begin(); i != folderList.end(); ++i) { - class WaitOnLockHandler : public DirLockCallback + const std::set<Zstring> folderList = getFolders(directoryPairsFormatted); + for (std::set<Zstring>::const_iterator i = folderList.begin(); i != folderList.end(); ++i) { - public: - WaitOnLockHandler(StatusHandler& statusUpdater) : waitHandler(statusUpdater) {} - - virtual void requestUiRefresh() //allowed to throw exceptions + class WaitOnLockHandler : public DirLockCallback + { + public: + WaitOnLockHandler(StatusHandler& statusUpdater) : waitHandler(statusUpdater) {} + + virtual void requestUiRefresh() //allowed to throw exceptions + { + waitHandler.requestUiRefresh(); + } + virtual void reportInfo(const Zstring& text) + { + waitHandler.reportInfo(text); + } + private: + StatusHandler& waitHandler; + } callback(*statusUpdater); + + try { - waitHandler.requestUiRefresh(); + lockHolder.insert(std::make_pair(*i, DirLock(*i + Zstr("sync.") + LOCK_FILE_ENDING, &callback))); } - virtual void updateStatusText(const Zstring& text) + catch (const FileError& e) { - waitHandler.updateStatusText(text); + bool dummy = false; //this warning shall not be shown but logged only + statusUpdater->reportWarning(e.msg(), dummy); } - private: - StatusHandler& waitHandler; - } callback(*statusUpdater); - - try - { - lockHolder.insert(std::make_pair(*i, DirLock(*i + DefaultStr("Sync.") + LOCK_FILE_ENDING, &callback))); - } - catch (const FileError& e) - { - bool dummy = false; //this warning shall not be shown but logged only - statusUpdater->reportWarning(e.msg(), dummy); } } @@ -767,30 +804,11 @@ wxString getConflictSameDateDiffSize(const FileMapping& fileObj) } -//check for files that have a difference in file modification date below 1 hour when DST check is active -template <class FileOrLinkMapping> -wxString getConflictChangeWithinHour(const FileOrLinkMapping& fileObj) -{ - //some beautification... - wxString left = wxString(_("Left")) + wxT(": "); - wxString right = wxString(_("Right")) + wxT(": "); - 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\".)"); - msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileObj.template getRelativeName<LEFT_SIDE>()) + wxT("\"")); - msg += wxT("\n\n"); - msg += left + wxT("\t") + _("Date") + wxT(": ") + utcTimeToLocalString(fileObj.template getLastWriteTime<LEFT_SIDE>()) + wxT("\n"); - msg += right + wxT("\t") + _("Date") + wxT(": ") + utcTimeToLocalString(fileObj.template getLastWriteTime<RIGHT_SIDE>()); - return wxString(_("Conflict detected:")) + wxT("\n") + msg; -} - //----------------------------------------------------------------------------- class CmpFileTime { public: - CmpFileTime(bool ignoreOneHourDifference, size_t tolerance) : - ignoreOneHourDifference_(ignoreOneHourDifference), + CmpFileTime(size_t tolerance) : tolerance_(tolerance) {} enum Result @@ -799,8 +817,7 @@ public: TIME_LEFT_NEWER, TIME_RIGHT_NEWER, TIME_LEFT_INVALID, - TIME_RIGHT_INVALID, - TIME_DST_CHANGE_WITHIN_HOUR + TIME_RIGHT_INVALID }; Result getResult(const wxLongLong& lhs, const wxLongLong& rhs) const @@ -821,16 +838,6 @@ public: if (sameFileTime(lhs, rhs, tolerance_)) //last write time may differ by up to 2 seconds (NTFS vs FAT32) return TIME_EQUAL; - //DST +/- 1-hour check: test if time diff is exactly +/- 1-hour (respecting 2 second FAT precision) - if (ignoreOneHourDifference_ && sameFileTime(lhs, rhs, 3600 + 2)) - { - //date diff < 1 hour is a conflict: it's not safe to determine which file is newer - if (sameFileTime(lhs, rhs, 3600 - 2 - 1)) - return TIME_DST_CHANGE_WITHIN_HOUR; - else //exact +/- 1-hour detected: treat as equal - return TIME_EQUAL; - } - //regular time comparison if (lhs < rhs) return TIME_RIGHT_NEWER; @@ -847,7 +854,6 @@ private: return a <= b + tolerance; } - const bool ignoreOneHourDifference_; const size_t tolerance_; }; @@ -866,7 +872,7 @@ void CompareProcess::categorizeSymlinkByTime(SymLinkMapping* linkObj) const return; } - switch (CmpFileTime(ignoreOneHourDifference, fileTimeTolerance).getResult(linkObj->getLastWriteTime<LEFT_SIDE>(), linkObj->getLastWriteTime<RIGHT_SIDE>())) + switch (CmpFileTime(fileTimeTolerance).getResult(linkObj->getLastWriteTime<LEFT_SIDE>(), linkObj->getLastWriteTime<RIGHT_SIDE>())) { case CmpFileTime::TIME_EQUAL: if ( @@ -898,10 +904,6 @@ void CompareProcess::categorizeSymlinkByTime(SymLinkMapping* linkObj) const case CmpFileTime::TIME_RIGHT_INVALID: linkObj->setCategoryConflict(getConflictInvalidDate(linkObj->getFullName<RIGHT_SIDE>(), linkObj->getLastWriteTime<RIGHT_SIDE>())); break; - - case CmpFileTime::TIME_DST_CHANGE_WITHIN_HOUR: - linkObj->setCategoryConflict(getConflictChangeWithinHour(*linkObj)); - break; } } @@ -927,7 +929,7 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo std::for_each(uncategorizedLinks.begin(), uncategorizedLinks.end(), boost::bind(&CompareProcess::categorizeSymlinkByTime, this, _1)); //categorize files that exist on both sides - const CmpFileTime timeCmp(ignoreOneHourDifference, fileTimeTolerance); + const CmpFileTime timeCmp(fileTimeTolerance); for (std::vector<FileMapping*>::iterator i = uncategorizedFiles.begin(); i != uncategorizedFiles.end(); ++i) { @@ -957,10 +959,6 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo case CmpFileTime::TIME_RIGHT_INVALID: line->setCategoryConflict(getConflictInvalidDate(line->getFullName<RIGHT_SIDE>(), line->getLastWriteTime<RIGHT_SIDE>())); break; - - case CmpFileTime::TIME_DST_CHANGE_WITHIN_HOUR: - line->setCategoryConflict(getConflictChangeWithinHour(*line)); - break; } } } @@ -1046,8 +1044,8 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director FileMapping* const gridline = *j; Zstring statusText = txtComparingContentOfFiles; - statusText.Replace(DefaultStr("%x"), gridline->getRelativeName<LEFT_SIDE>(), false); - statusUpdater->updateStatusText(statusText); + statusText.Replace(Zstr("%x"), gridline->getRelativeName<LEFT_SIDE>(), false); + statusUpdater->reportInfo(statusText); //check files that exist in left and right model but have different content while (true) @@ -1269,7 +1267,7 @@ void CompareProcess::performBaseComparison(BaseDirMapping& output, std::vector<F output.getFilter()); - statusUpdater->updateStatusText(wxToZ(_("Generating file list..."))); + statusUpdater->reportInfo(wxToZ(_("Generating file list..."))); statusUpdater->forceUiRefresh(); //keep total number of scanned files up to date //PERF_STOP; diff --git a/comparison.h b/comparison.h index ac22104c..7ed54eeb 100644 --- a/comparison.h +++ b/comparison.h @@ -43,7 +43,6 @@ class CompareProcess public: CompareProcess(SymLinkHandling handleSymlinks, size_t fileTimeTol, - bool ignoreOneHourDiff, xmlAccess::OptionalDialogs& warnings, StatusHandler* handler); @@ -66,7 +65,6 @@ private: boost::shared_ptr<DirectoryBuffer> directoryBuffer; //std::auto_ptr does not work with forward declarations (Or we need a non-inline ~CompareProcess())! const size_t fileTimeTolerance; //max allowed file time deviation - const bool ignoreOneHourDifference; xmlAccess::OptionalDialogs& m_warnings; diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp index e8cb78f0..84ed0162 100644 --- a/file_hierarchy.cpp +++ b/file_hierarchy.cpp @@ -193,13 +193,13 @@ const Zstring& ffs3::getSyncDBFilename() //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories #ifdef FFS_WIN static Zstring output = Zstring(util::is64BitBuild ? - DefaultStr("sync.x64.") : - DefaultStr("sync.")) + SYNC_DB_FILE_ENDING; + Zstr("sync.x64.") : + Zstr("sync.")) + SYNC_DB_FILE_ENDING; #elif defined FFS_LINUX //files beginning with dots are hidden e.g. in Nautilus static Zstring output = Zstring(util::is64BitBuild ? - DefaultStr(".sync.x64.") : - DefaultStr(".sync.")) + SYNC_DB_FILE_ENDING; + Zstr(".sync.x64.") : + Zstr(".sync.")) + SYNC_DB_FILE_ENDING; #endif return output; } diff --git a/file_hierarchy.h b/file_hierarchy.h index 2726d2c2..d03184a1 100644 --- a/file_hierarchy.h +++ b/file_hierarchy.h @@ -173,7 +173,7 @@ private: //------------------------------------------------------------------ //save/load full directory information const Zstring& getSyncDBFilename(); //get short filename of database file -const Zstring SYNC_DB_FILE_ENDING = DefaultStr("ffs_db"); +const Zstring SYNC_DB_FILE_ENDING = Zstr("ffs_db"); //------------------------------------------------------------------ /* class hierarchy: @@ -234,8 +234,8 @@ public: protected: //constructor used by DirMapping HierarchyObject(const HierarchyObject& parent, const Zstring& shortName) : - relNamePf(parent.getRelativeNamePf() + shortName + common::FILE_NAME_SEPARATOR), - baseDirLeft(parent.baseDirLeft), + relNamePf( parent.getRelativeNamePf() + shortName + common::FILE_NAME_SEPARATOR), + baseDirLeft( parent.baseDirLeft), baseDirRight(parent.baseDirRight) {} //constructor used by BaseDirMapping @@ -1333,7 +1333,7 @@ const Zstring FileMapping::getExtension() const //attention: Zstring::AfterLast() returns whole string if char not found! -> don't use const Zstring& shortName = getShortName<side>(); - const size_t pos = shortName.Find(DefaultChar('.'), true); + const size_t pos = shortName.rfind(Zchar('.')); return pos == Zstring::npos ? Zstring() : Zstring(shortName.c_str() + pos + 1); diff --git a/library/custom_grid.cpp b/library/custom_grid.cpp index 2537f529..b510717f 100644 --- a/library/custom_grid.cpp +++ b/library/custom_grid.cpp @@ -18,6 +18,7 @@ #include <wx/dcclient.h> #include "icon_buffer.h" #include <wx/icon.h> +#include <wx/tooltip.h> #ifdef FFS_WIN #include <wx/timer.h> @@ -380,12 +381,12 @@ protected: virtual void visit(const SymLinkMapping& linkObj) { iconName = linkObj.getLinkType<side>() == LinkDescriptor::TYPE_DIR ? - DefaultStr("folder") : + Zstr("folder") : linkObj.getFullName<side>(); } virtual void visit(const DirMapping& dirObj) { - iconName = DefaultStr("folder"); + iconName = Zstr("folder"); } Zstring iconName; @@ -580,10 +581,9 @@ CustomGrid::CustomGrid(wxWindow *parent, isLeading(false), m_marker(-1, ASCENDING) { - //set color of selections - wxColour darkBlue(40, 35, 140); - SetSelectionBackground(darkBlue); - SetSelectionForeground(*wxWHITE); + //wxColour darkBlue(40, 35, 140); -> user default colors instead! + //SetSelectionBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); + //SetSelectionForeground(*wxWHITE); } @@ -975,6 +975,22 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col) } +std::pair<int, int> CustomGrid::mousePosToCell(wxPoint pos) +{ + int x = -1; + int y = -1; + CalcUnscrolledPosition(pos.x, pos.y, &x, &y); + + std::pair<int, int> output(-1, -1); + if (x >= 0 && y >= 0) + { + output.first = YToRow(y); + output.second = XToCol(x); + } + return output; +} + + std::set<size_t> CustomGrid::getAllSelectedRows() const { std::set<size_t> output; @@ -1075,7 +1091,7 @@ public: if (!fileName.empty()) { //first check if it is a directory icon: - if (fileName == DefaultStr("folder")) + if (fileName == Zstr("folder")) { 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 @@ -1159,8 +1175,57 @@ CustomGridRim::CustomGridRim(wxWindow *parent, const wxSize& size, long style, const wxString& name) : - CustomGrid(parent, id, pos, size, style, name), fileIconsAreEnabled(false) -{} + CustomGrid(parent, id, pos, size, style, name), fileIconsAreEnabled(false) {} + + +template <SelectedSide side> +void CustomGridRim::setTooltip(const wxMouseEvent& event) +{ + const int hoveredRow = mousePosToCell(event.GetPosition()).first; + + wxString toolTip; + if (hoveredRow >= 0 && getGridDataTable() != NULL) + { + const FileSystemObject* const fsObj = getGridDataTable()->getRawData(hoveredRow); + if (fsObj && !fsObj->isEmpty<side>()) + { + struct AssembleTooltip : public FSObjectVisitor + { + AssembleTooltip(wxString& tipMsg) : tipMsg_(tipMsg) {} + + virtual void visit(const FileMapping& fileObj) + { + tipMsg_ = zToWx(fileObj.getShortName<side>()) + wxT("\n") + + _("Size") + wxT(": ") + ffs3::formatFilesizeToShortString(fileObj.getFileSize<side>()) + wxT("\n") + + _("Date") + wxT(": ") + ffs3::utcTimeToLocalString(fileObj.getLastWriteTime<side>()); + } + + virtual void visit(const SymLinkMapping& linkObj) + { + tipMsg_ = zToWx(linkObj.getShortName<side>()) + wxT("\n") + + _("Date") + wxT(": ") + ffs3::utcTimeToLocalString(linkObj.getLastWriteTime<side>()); + } + + virtual void visit(const DirMapping& dirObj) + { + tipMsg_ = zToWx(dirObj.getShortName<side>()); + } + + wxString& tipMsg_; + } assembler(toolTip); + fsObj->accept(assembler); + } + } + + wxToolTip* tt = GetGridWindow()->GetToolTip(); + if (!tt) + //wxWidgets bug: tooltip multiline property is defined by first tooltip text containing newlines or not (same is true for maximum width) + GetGridWindow()->SetToolTip(new wxToolTip(wxT("a b\n\ + a b"))); //ugly, but is working (on Windows) + tt = GetGridWindow()->GetToolTip(); //should be bound by now + if (tt && tt->GetTip() != toolTip) + tt->SetTip(toolTip); +} void CustomGridRim::updateGridSizes() @@ -1425,12 +1490,9 @@ CustomGridRim::VisibleRowRange CustomGridRim::getVisibleRows() if (height >= 0) { - int topRowY = -1; - CalcUnscrolledPosition(0, 0, &dummy, &topRowY); - - if (topRowY >= 0) + const int topRow = mousePosToCell(wxPoint(0, 0)).first; + if (topRow >= 0) { - const int topRow = YToRow(topRowY); const int rowCount = static_cast<int>(ceil(height / static_cast<double>(GetDefaultRowSize()))); // = height / rowHeight rounded up const int bottomRow = topRow + rowCount - 1; @@ -1535,7 +1597,17 @@ CustomGridLeft::CustomGridLeft(wxWindow *parent, long style, const wxString& name) : CustomGridRim(parent, id, pos, size, style, name), - gridDataTable(NULL) {} + gridDataTable(NULL) +{ + GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridLeft::OnMouseMovement), NULL, this); //row-based tooltip +} + + +void CustomGridLeft::OnMouseMovement(wxMouseEvent& event) +{ + CustomGridRim::setTooltip<LEFT_SIDE>(event); + event.Skip(); +} bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) @@ -1583,7 +1655,17 @@ CustomGridRight::CustomGridRight(wxWindow *parent, long style, const wxString& name) : CustomGridRim(parent, id, pos, size, style, name), - gridDataTable(NULL) {} + gridDataTable(NULL) +{ + GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridRight::OnMouseMovement), NULL, this); //row-based tooltip +} + + +void CustomGridRight::OnMouseMovement(wxMouseEvent& event) +{ + CustomGridRim::setTooltip<RIGHT_SIDE>(event); + event.Skip(); +} bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) @@ -1717,16 +1799,21 @@ void CustomGridMiddle::setGridDataTable(const GridView* gridDataView) //called o void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event) { - const int highlightedRowOld = highlightedRow; + const int rowOld = highlightedRow; + const BlockPosition posOld = highlightedPos; + if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse { highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos); - if (highlightedRow >= 0) + + if (rowOld != highlightedRow) + { + RefreshCell(highlightedRow, 0); + RefreshCell(rowOld, 0); + } + else if (posOld != highlightedPos) RefreshCell(highlightedRow, 0); - if ( highlightedRowOld >= 0 && - highlightedRow != highlightedRowOld) - RefreshCell(highlightedRowOld, 0); //handle tooltip showToolTip(highlightedRow, GetGridWindow()->ClientToScreen(event.GetPosition())); @@ -1830,7 +1917,7 @@ void CustomGridMiddle::OnLeftMouseDown(wxMouseEvent& event) void CustomGridMiddle::OnLeftMouseUp(wxMouseEvent& event) { - const int rowEndFiltering = mousePosToRow(event.GetPosition()); + const int rowEndFiltering = mousePosToCell(event.GetPosition()).first; if (0 <= selectionRowBegin && 0 <= rowEndFiltering) { @@ -1874,7 +1961,7 @@ void CustomGridMiddle::OnLeftMouseUp(wxMouseEvent& event) } -int CustomGridMiddle::mousePosToRow(const wxPoint pos, BlockPosition* block) +int CustomGridMiddle::mousePosToRow(wxPoint pos, BlockPosition* block) { int row = -1; int x = -1; diff --git a/library/custom_grid.h b/library/custom_grid.h index 6c35ffbe..206841dd 100644 --- a/library/custom_grid.h +++ b/library/custom_grid.h @@ -13,6 +13,8 @@ #include <map> #include <memory> #include <set> +#include "../file_hierarchy.h" + class CustomGridTableRim; class CustomGridTableLeft; @@ -85,8 +87,8 @@ public: protected: void RefreshCell(int row, int col); - virtual void DrawColLabel(wxDC& dc, int col); + std::pair<int, int> mousePosToCell(wxPoint pos); //returns (row/column) pair private: virtual void setGridDataTable(const ffs3::GridView* gridDataView) = 0; @@ -161,6 +163,10 @@ public: void enableFileIcons(const bool value); +protected: + template <ffs3::SelectedSide side> + void setTooltip(const wxMouseEvent& event); + private: CustomGridTableRim* getGridDataTable(); virtual const CustomGridTableRim* getGridDataTable() const = 0; @@ -198,6 +204,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); private: + void OnMouseMovement(wxMouseEvent& event); virtual void setGridDataTable(const ffs3::GridView* gridDataView); virtual const CustomGridTableRim* getGridDataTable() const; @@ -221,6 +228,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); private: + void OnMouseMovement(wxMouseEvent& event); virtual void setGridDataTable(const ffs3::GridView* gridDataView); virtual const CustomGridTableRim* getGridDataTable() const; diff --git a/library/db_file.cpp b/library/db_file.cpp index 1daa51f5..195d7df6 100644 --- a/library/db_file.cpp +++ b/library/db_file.cpp @@ -189,7 +189,7 @@ public: DbStreamData loadFile(const Zstring& filename) //throw (FileError) { if (!ffs3::fileExists(filename)) - throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") + + throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") + _("One of the FreeFileSync database files is not yet existing:") + wxT(" \n") + wxT("\"") + zToWx(filename) + wxT("\"")); @@ -217,14 +217,15 @@ std::pair<DirInfoPtr, DirInfoPtr> ffs3::loadFromDisk(const BaseDirMapping& baseM //find associated DirInfo-streams DirectoryTOC::const_iterator dbLeft = dbEntriesLeft.second.find(dbEntriesRight.first); //find left db-entry that corresponds to right database + DirectoryTOC::const_iterator dbRight = dbEntriesRight.second.find(dbEntriesLeft.first); //find left db-entry that corresponds to right database + if (dbLeft == dbEntriesLeft.second.end()) - throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") + + throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") + _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") + wxT("\"") + zToWx(fileNameLeft) + wxT("\"")); - DirectoryTOC::const_iterator dbRight = dbEntriesRight.second.find(dbEntriesLeft.first); //find left db-entry that corresponds to right database if (dbRight == dbEntriesRight.second.end()) - throw FileError(wxString(_("Initial synchronization:")) + wxT(" \n\n") + + throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") + _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") + wxT("\"") + zToWx(fileNameRight) + wxT("\"")); @@ -397,8 +398,8 @@ bool entryExisting(const DirectoryTOC& table, const util::UniqueId& newKey, cons void ffs3::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError) { //transactional behaviour! write to tmp files first - const Zstring fileNameLeftTmp = baseMapping.getDBFilename<LEFT_SIDE>() + DefaultStr(".tmp"); - const Zstring fileNameRightTmp = baseMapping.getDBFilename<RIGHT_SIDE>() + DefaultStr(".tmp");; + const Zstring fileNameLeftTmp = baseMapping.getDBFilename<LEFT_SIDE>() + Zstr(".tmp"); + const Zstring fileNameRightTmp = baseMapping.getDBFilename<RIGHT_SIDE>() + Zstr(".tmp");; //delete old tmp file, if necessary -> throws if deletion fails! removeFile(fileNameLeftTmp); // diff --git a/library/db_file.h b/library/db_file.h index 8e1f9c94..ea9d68ad 100644 --- a/library/db_file.h +++ b/library/db_file.h @@ -20,7 +20,13 @@ struct DirInformation }; typedef boost::shared_ptr<const DirInformation> DirInfoPtr; -std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw (FileError) -> return value always bound! +class FileErrorDatabaseNotExisting : public FileError +{ +public: + FileErrorDatabaseNotExisting(const wxString& message) : FileError(message) {} +}; + +std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw (FileError, FileErrorDatabaseNotExisting) -> return value always bound! } #endif // DBFILE_H_INCLUDED diff --git a/library/dir_lock.cpp b/library/dir_lock.cpp index c5ea37b1..54ae8636 100644 --- a/library/dir_lock.cpp +++ b/library/dir_lock.cpp @@ -6,21 +6,25 @@ #include <wx/timer.h> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> -#include <boost/thread.hpp> +#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp> #include "../shared/loki/ScopeGuard.h" #include <wx/msgdlg.h> #include "../shared/system_constants.h" #include "../shared/guid.h" #include "../shared/file_io.h" #include <utility> +#include "../shared/serialize.h" #ifdef FFS_WIN +#include <tlhelp32.h> #include <wx/msw/wrapwin.h> //includes "windows.h" #include "../shared/long_path_prefix.h" #elif defined FFS_LINUX +#include "../shared/file_handling.h" #include <sys/stat.h> #include <cerrno> +#include <unistd.h> #endif using namespace ffs3; @@ -32,13 +36,15 @@ namespace const size_t EMIT_LIFE_SIGN_INTERVAL = 5000; //show life sign; unit [ms] const size_t POLL_LIFE_SIGN_INTERVAL = 6000; //poll for life sign; unit [ms] const size_t DETECT_EXITUS_INTERVAL = 30000; //assume abandoned lock; unit [ms] + +typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class } class LifeSigns { public: - LifeSigns(const Zstring& lockfilename) : //throw()!!! siehe SharedDirLock() - lockfilename_(lockfilename.c_str()) //ref-counting structure is used by thread: make deep copy! + LifeSigns(const BasicString& lockfilename) : //throw()!!! siehe SharedDirLock() + lockfilename_(lockfilename) //thread safety: make deep copy! { threadObj = boost::thread(boost::cref(*this)); //localize all thread logic to this class! } @@ -72,7 +78,7 @@ public: const char buffer[1] = {' '}; #ifdef FFS_WIN - const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_).c_str(), + const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_.c_str()).c_str(), FILE_APPEND_DATA, FILE_SHARE_READ, NULL, @@ -115,7 +121,7 @@ private: LifeSigns& operator=(const LifeSigns&); // boost::thread threadObj; - const Zstring lockfilename_; //used by worker thread only! Not ref-counted! + const BasicString lockfilename_; //used by worker thread only! Not ref-counted! }; @@ -157,7 +163,8 @@ wxULongLong getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo const DWORD lastError = ::GetLastError(); const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"") + wxT("\n\n") + getLastErrorFormatted(lastError); - if (lastError == ERROR_FILE_NOT_FOUND) + if ( lastError == ERROR_FILE_NOT_FOUND || + lastError == ERROR_PATH_NOT_FOUND) throw ErrorNotExisting(errorMessage); else throw FileError(errorMessage); @@ -187,29 +194,138 @@ wxULongLong getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo Zstring deleteAbandonedLockName(const Zstring& lockfilename) { - const size_t pos = lockfilename.Find(common::FILE_NAME_SEPARATOR, true); //search from end - - return pos == Zstring::npos ? DefaultStr("Del.") + lockfilename : - + const size_t pos = lockfilename.rfind(common::FILE_NAME_SEPARATOR); //search from end + return pos == Zstring::npos ? Zstr("Del.") + lockfilename : Zstring(lockfilename.c_str(), pos + 1) + //include path separator - DefaultStr("Del.") + + Zstr("Del.") + lockfilename.AfterLast(common::FILE_NAME_SEPARATOR); //returns the whole string if ch not found } -void writeLockId(const Zstring& lockfilename) //throw (FileError) +namespace +{ +inline +wxString readString(wxInputStream& stream) //read string from file stream +{ + const size_t strLength = util::readNumber<size_t>(stream); + boost::scoped_array<wxChar> buffer(new wxChar[strLength]); + stream.Read(buffer.get(), sizeof(wxChar) * strLength); + return wxString(buffer.get(), strLength); +} + + +inline +void writeString(wxOutputStream& stream, const wxString& str) //write string to filestream +{ + util::writeNumber<size_t>(stream, str.length()); + stream.Write(str.c_str(), sizeof(wxChar) * str.length()); +} + + +struct LockInformation +{ + LockInformation() + { +#ifdef FFS_WIN + processId = ::GetCurrentProcessId(); +#elif defined FFS_LINUX + processId = ::getpid(); +#endif + computerId = ::wxGetFullHostName(); + } + + LockInformation(wxInputStream& stream) : //read + lockId(util::UniqueId(stream)) + { + processId = util::readNumber<ProcessId>(stream); + computerId = readString(stream); + } + + void toStream(wxOutputStream& stream) const //write + { + lockId.toStream(stream); + util::writeNumber<ProcessId>(stream, processId); + writeString(stream, computerId); + } + +#ifdef FFS_WIN + typedef DWORD ProcessId; +#elif defined FFS_LINUX + typedef pid_t ProcessId; +#endif + + util::UniqueId lockId; + ProcessId processId; + wxString computerId; +}; + + +//true: process not available, false: cannot say anything +enum ProcessStatus +{ + PROC_STATUS_NOT_RUNNING, + PROC_STATUS_RUNNING, + PROC_STATUS_NO_IDEA +}; +ProcessStatus getProcessStatus(LockInformation::ProcessId procId, const wxString& computerId) +{ + if (::wxGetFullHostName() != computerId || computerId.empty()) + return PROC_STATUS_NO_IDEA; //lock owned by different computer + +#ifdef FFS_WIN + //note: ::OpenProcess() is no option as it may successfully return for crashed processes! + HANDLE snapshot = ::CreateToolhelp32Snapshot( + TH32CS_SNAPPROCESS, //__in DWORD dwFlags, + procId); //__in DWORD th32ProcessID + if (snapshot == INVALID_HANDLE_VALUE) + return PROC_STATUS_NO_IDEA; + boost::shared_ptr<void> dummy(snapshot, ::CloseHandle); + + PROCESSENTRY32 processEntry = {}; + processEntry.dwSize = sizeof(processEntry); + + if (!::Process32First(snapshot, //__in HANDLE hSnapshot, + &processEntry)) //__inout LPPROCESSENTRY32 lppe + return PROC_STATUS_NO_IDEA; + + do + { + if (processEntry.th32ProcessID == procId) + return PROC_STATUS_RUNNING; //process still running + } + while(::Process32Next(snapshot, &processEntry)); + + return PROC_STATUS_NOT_RUNNING; + +#elif defined FFS_LINUX + if (procId <= 0 || procId >= 65536) + return PROC_STATUS_NO_IDEA; //invalid process id + + return ffs3::dirExists(Zstr("/proc/") + Zstring::fromNumber(procId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING; +#endif +} + + +void writeLockInfo(const Zstring& lockfilename) //throw (FileError) { //write GUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks ,etc.) FileOutputStream lockFile(lockfilename); //throw FileError() - util::UniqueId().toStream(lockFile); // + LockInformation().toStream(lockFile); } -util::UniqueId retrieveLockId(const Zstring& lockfilename) //throw (FileError, ErrorNotExisting) +LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw (FileError, ErrorNotExisting) { //read GUID from beginning of file FileInputStream lockFile(lockfilename); //throw (FileError, ErrorNotExisting) - return util::UniqueId(lockFile); // + return LockInformation(lockFile); +} + + +util::UniqueId retrieveLockId(const Zstring& lockfilename) //throw (FileError, ErrorNotExisting) +{ + return retrieveLockInfo(lockfilename).lockId; +} } @@ -217,12 +333,13 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr { Zstring infoMsg; infoMsg = wxToZ(_("Waiting while directory is locked (%x)...")); - infoMsg.Replace(DefaultStr("%x"), DefaultStr("\"") + lockfilename + DefaultStr("\"")); - if (callback) callback->updateStatusText(infoMsg); + infoMsg.Replace(Zstr("%x"), Zstr("\"") + lockfilename + Zstr("\"")); + if (callback) callback->reportInfo(infoMsg); //--------------------------------------------------------------- try { - const util::UniqueId lockId = retrieveLockId(lockfilename); //throw (FileError, ErrorNotExisting) + const LockInformation lockInfo = retrieveLockInfo(lockfilename); //throw (FileError, ErrorNotExisting) + const bool lockOwnderDead = getProcessStatus(lockInfo.processId, lockInfo.computerId) == PROC_STATUS_NOT_RUNNING; //convenience optimization: if we know the owning process crashed, we needn't wait DETECT_EXITUS_INTERVAL sec wxULongLong fileSizeOld; wxLongLong lockSilentStart = wxGetLocalTimeMillis(); @@ -238,24 +355,20 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr fileSizeOld = fileSizeNew; lockSilentStart = currentTime; } - else if (currentTime - lockSilentStart > DETECT_EXITUS_INTERVAL) + + if ( lockOwnderDead || //no need to wait any longer... + currentTime - lockSilentStart > DETECT_EXITUS_INTERVAL) { DirLock dummy(deleteAbandonedLockName(lockfilename), callback); //throw (FileError) //now that the lock is in place check existence again: meanwhile another process may have deleted and created a new lock! - if (retrieveLockId(lockfilename) != lockId) //throw (FileError, ErrorNotExisting) + if (retrieveLockId(lockfilename) != lockInfo.lockId) //throw (FileError, ErrorNotExisting) return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over... if (getLockFileSize(lockfilename) != fileSizeOld) //throw (FileError, ErrorNotExisting) continue; //belated lifesign - //--------------------------------------------------------------- - Zstring infoMsg2 = wxToZ(_("Removing abandoned directory lock (%x)...")); - infoMsg2.Replace(DefaultStr("%x"), DefaultStr("\"") + lockfilename + DefaultStr("\"")); - if (callback) callback->updateStatusText(infoMsg2); - //--------------------------------------------------------------- - ::deleteLockFile(lockfilename); //throw (FileError) return; } @@ -276,11 +389,11 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr remainingSeconds = std::max(0L, remainingSeconds); Zstring remSecMsg = wxToZ(_("%x sec")); - remSecMsg.Replace(DefaultStr("%x"), numberToZstring(remainingSeconds)); - callback->updateStatusText(infoMsg + DefaultStr(" ") + remSecMsg); + remSecMsg.Replace(Zstr("%x"), Zstring::fromNumber(remainingSeconds)); + callback->reportInfo(infoMsg + Zstr(" ") + remSecMsg); } else - callback->updateStatusText(infoMsg); //emit a message in any case (might clear other one) + callback->reportInfo(infoMsg); //emit a message in any case (might clear other one) } } } @@ -341,7 +454,7 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError) Loki::ScopeGuard guardLockFile = Loki::MakeGuard(::releaseLock, lockfilename); //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks ,etc.) - writeLockId(lockfilename); //throw (FileError) + writeLockInfo(lockfilename); //throw (FileError) guardLockFile.Dismiss(); //lockfile created successfully return true; @@ -358,7 +471,7 @@ public: while (!::tryLock(lockfilename)) //throw (FileError) ::waitOnDirLock(lockfilename, callback); // - emitLifeSigns.reset(new LifeSigns(lockfilename)); //throw()! ownership of lockfile not yet managed! + emitLifeSigns.reset(new LifeSigns(lockfilename.c_str())); //throw()! ownership of lockfile not yet managed! } ~SharedDirLock() @@ -378,7 +491,7 @@ private: }; -class DirLock::LockAdmin //administrate all locks of this process to avoid deadlock by recursion +class DirLock::LockAdmin //administrate all locks held by this process to avoid deadlock by recursion { public: static LockAdmin& instance() diff --git a/library/dir_lock.h b/library/dir_lock.h index e3b6597c..fba65d2b 100644 --- a/library/dir_lock.h +++ b/library/dir_lock.h @@ -10,7 +10,7 @@ struct DirLockCallback //while waiting for the lock { virtual ~DirLockCallback() {} virtual void requestUiRefresh() = 0; //allowed to throw exceptions - virtual void updateStatusText(const Zstring& text) = 0; + virtual void reportInfo(const Zstring& text) = 0; }; /* @@ -18,7 +18,7 @@ RAII structure to place a directory lock against other FFS processes: - recursive locking supported, even with alternate lockfile names, e.g. via symlinks, network mounts etc. - ownership shared between all object instances refering to a specific lock location(= UUID) - can be copied safely and efficiently! (ref-counting) - - detects and resolves abandoned locks + - detects and resolves abandoned locks (instantly if lock is associated with local pc, else after 30 seconds) - race-free (Windows, almost on Linux) */ class DirLock diff --git a/library/error_log.h b/library/error_log.h index dc3ef580..876f78b9 100644 --- a/library/error_log.h +++ b/library/error_log.h @@ -9,8 +9,8 @@ #include <wx/string.h> #include <vector> +#include "../shared/zstring.h" -class Zstring; namespace ffs3 { diff --git a/library/filter.cpp b/library/filter.cpp index c4bc69d7..7697ea4b 100644 --- a/library/filter.cpp +++ b/library/filter.cpp @@ -59,11 +59,11 @@ BaseFilter::FilterRef BaseFilter::loadFilter(wxInputStream& stream) const Zstring uniqueClassId = util::readString(stream); //read actual object - if (uniqueClassId == DefaultStr("NullFilter")) + if (uniqueClassId == Zstr("NullFilter")) return NullFilter::load(stream); - else if (uniqueClassId == DefaultStr("NameFilter")) + else if (uniqueClassId == Zstr("NameFilter")) return NameFilter::load(stream); - else if (uniqueClassId == DefaultStr("CombinedFilter")) + else if (uniqueClassId == Zstr("CombinedFilter")) return CombinedFilter::load(stream); else throw std::logic_error("Programming Error: Unknown filter!"); @@ -78,15 +78,15 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st #ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case - filterFormatted.MakeUpper(); + MakeUpper(filterFormatted); #elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case: nothing to do here #endif - static const Zstring sepAsterisk = Zstring() + common::FILE_NAME_SEPARATOR + DefaultChar('*'); - static const Zstring sepQuestionMark = Zstring() + common::FILE_NAME_SEPARATOR + DefaultChar('?'); - static const Zstring asteriskSep = Zstring(DefaultStr("*")) + common::FILE_NAME_SEPARATOR; - static const Zstring questionMarkSep = Zstring(DefaultStr("?")) + common::FILE_NAME_SEPARATOR; + static const Zstring sepAsterisk = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('*'); + static const Zstring sepQuestionMark = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('?'); + static const Zstring asteriskSep = Zstring(Zchar('*')) + common::FILE_NAME_SEPARATOR; + static const Zstring questionMarkSep = Zstring(Zchar('?')) + common::FILE_NAME_SEPARATOR; //-------------------------------------------------------------------------------------------------- //add some syntactic sugar: handle beginning of filtername @@ -127,49 +127,77 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st } -class MatchFound : public std::unary_function<Zstring, bool> +namespace { -public: - MatchFound(const Zstring& name) : name_(name) {} - - bool operator()(const Zstring& mask) const +template <class T> +inline +const T* cStringFind(const T* str1, T ch) //strchr() +{ + while (*str1 != ch) //ch is allowed to be 0 by contract! must return end of string in this case { - return Zstring::Matches(name_.c_str(), mask.c_str()); + if (*str1 == 0) + return NULL; + ++str1; } -private: - const Zstring& name_; -}; + return str1; +} -inline -bool matchesFilter(const Zstring& name, const std::set<Zstring>& filter) +bool matchesMask(const Zchar* string, const Zchar* mask) { -#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case - Zstring nameFormatted = name; - nameFormatted.MakeUpper(); -#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case - const Zstring& nameFormatted = name; //nothing to do here -#endif + for (Zchar ch; (ch = *mask) != 0; ++mask, ++string) + { + switch (ch) + { + case Zchar('?'): + if (*string == 0) + return false; + break; - return std::find_if(filter.begin(), filter.end(), MatchFound(nameFormatted)) != filter.end(); -} + case Zchar('*'): + //advance to next non-*/? char + do + { + ++mask; + ch = *mask; + } + while (ch == Zchar('*') || ch == Zchar('?')); + //if match ends with '*': + if (ch == 0) + return true; + + ++mask; + while ((string = cStringFind(string, ch)) != NULL) + { + ++string; + if (matchesMask(string, mask)) + return true; + } + return false; + default: + if (*string != ch) + return false; + } + } + return *string == 0; +} //returns true if string matches at least the beginning of mask inline -bool matchesMaskBegin(const DefaultChar* string, const DefaultChar* mask) +bool matchesMaskBegin(const Zchar* string, const Zchar* mask) { - for (DefaultChar ch; (ch = *mask) != 0; ++mask, ++string) + for (Zchar ch; (ch = *mask) != 0; ++mask, ++string) { if (*string == 0) return true; switch (ch) { - case DefaultChar('?'): + case Zchar('?'): break; - case DefaultChar('*'): + case Zchar('*'): return true; default: @@ -179,18 +207,33 @@ bool matchesMaskBegin(const DefaultChar* string, const DefaultChar* mask) } return *string == 0; } +} + + +class MatchFound : public std::unary_function<Zstring, bool> +{ +public: + MatchFound(const Zstring& name) : name_(name) {} + + bool operator()(const Zstring& mask) const + { + return matchesMask(name_, mask); + } +private: + const Zstring& name_; +}; inline -bool matchesFilterBegin(const Zstring& name, const std::set<Zstring>& filter) +bool matchesFilter(const Zstring& nameFormatted, const std::set<Zstring>& filter) { -#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case - Zstring nameFormatted = name; - nameFormatted.MakeUpper(); -#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case - const Zstring& nameFormatted = name; //nothing to do here -#endif + return std::find_if(filter.begin(), filter.end(), MatchFound(nameFormatted)) != filter.end(); +} + +inline +bool matchesFilterBegin(const Zstring& nameFormatted, const std::set<Zstring>& filter) +{ return std::find_if(filter.begin(), filter.end(), boost::bind(matchesMaskBegin, nameFormatted.c_str(), _1)) != filter.end(); } @@ -201,10 +244,10 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) //delimiters may be ';' or '\n' std::vector<Zstring> output; - const std::vector<Zstring> filterPreProcessing = filterString.Tokenize(wxT(';')); + const std::vector<Zstring> filterPreProcessing = filterString.Split(Zchar(';')); for (std::vector<Zstring>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i) { - const std::vector<Zstring> newEntries = i->Tokenize(wxT('\n')); + const std::vector<Zstring> newEntries = i->Split(Zchar('\n')); output.insert(output.end(), newEntries.begin(), newEntries.end()); } @@ -231,8 +274,15 @@ NameFilter::NameFilter(const Zstring& includeFilter, const Zstring& excludeFilte bool NameFilter::passFileFilter(const Zstring& relFilename) const { - return matchesFilter(relFilename, filterFileIn) && //process include filters - !matchesFilter(relFilename, filterFileEx); //process exclude filters +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case + Zstring nameFormatted = relFilename; + MakeUpper(nameFormatted); +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case + const Zstring& nameFormatted = relFilename; //nothing to do here +#endif + + return matchesFilter(nameFormatted, filterFileIn) && //process include filters + !matchesFilter(nameFormatted, filterFileEx); //process exclude filters } @@ -240,18 +290,25 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch { assert(subObjMightMatch == NULL || *subObjMightMatch == true); //check correct usage - if (matchesFilter(relDirname, filterFolderEx)) //process exclude filters +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case + Zstring nameFormatted = relDirname; + MakeUpper(nameFormatted); +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case + const Zstring& nameFormatted = relDirname; //nothing to do here +#endif + + if (matchesFilter(nameFormatted, filterFolderEx)) //process exclude filters { if (subObjMightMatch) *subObjMightMatch = false; //exclude subfolders/subfiles as well return false; } - if (!matchesFilter(relDirname, filterFolderIn)) //process include filters + if (!matchesFilter(nameFormatted, filterFolderIn)) //process include filters { if (subObjMightMatch) { - const Zstring& subNameBegin = relDirname + common::FILE_NAME_SEPARATOR; //const-ref optimization + const Zstring& subNameBegin = nameFormatted + common::FILE_NAME_SEPARATOR; //const-ref optimization *subObjMightMatch = matchesFilterBegin(subNameBegin, filterFileIn) || //might match a file in subdirectory matchesFilterBegin(subNameBegin, filterFolderIn); //or another subdirectory @@ -265,7 +322,7 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch bool NameFilter::isNull() const { - static NameFilter output(DefaultStr("*"), Zstring()); + static NameFilter output(Zstr("*"), Zstring()); return *this == output; } @@ -294,7 +351,7 @@ bool NameFilter::cmpLessSameType(const BaseFilter& other) const Zstring NameFilter::uniqueClassIdentifier() const { - return DefaultStr("NameFilter"); + return Zstr("NameFilter"); } diff --git a/library/filter.h b/library/filter.h index 9497eb8d..91caff7d 100644 --- a/library/filter.h +++ b/library/filter.h @@ -183,7 +183,7 @@ bool NullFilter::cmpLessSameType(const BaseFilter& other) const inline Zstring NullFilter::uniqueClassIdentifier() const { - return DefaultStr("NullFilter"); + return Zstr("NullFilter"); } @@ -227,7 +227,7 @@ bool CombinedFilter::cmpLessSameType(const BaseFilter& other) const inline Zstring CombinedFilter::uniqueClassIdentifier() const { - return DefaultStr("CombinedFilter"); + return Zstr("CombinedFilter"); } diff --git a/library/icon_buffer.cpp b/library/icon_buffer.cpp index 81d14146..20ff60f7 100644 --- a/library/icon_buffer.cpp +++ b/library/icon_buffer.cpp @@ -9,7 +9,6 @@ #include <map> #include <queue> #include <set> -#include <boost/thread.hpp> #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -24,43 +23,38 @@ using ffs3::IconBuffer; -namespace -{ #ifdef FFS_WIN -Zstring getFileExtension(const Zstring& filename) +IconBuffer::BasicString IconBuffer::getFileExtension(const BasicString& filename) { - const Zstring shortName = filename.AfterLast(DefaultChar('\\')); //warning: using windows file name separator! - const size_t pos = shortName.Find(DefaultChar('.'), true); - return pos == Zstring::npos ? - Zstring() : - Zstring(shortName.c_str() + pos + 1); + const BasicString shortName = filename.AfterLast(Zchar('\\')); //warning: using windows file name separator! + + return shortName.find(Zchar('.')) != BasicString::npos ? + filename.AfterLast(Zchar('.')) : + BasicString(); } //test for extension for icons that physically have to be retrieved from disc -bool isPriceyExtension(const Zstring& extension) +bool IconBuffer::isPriceyExtension(const IconBuffer::BasicString& extension) { - static std::set<Zstring, LessFilename> exceptions; - static bool isInitalized = false; - if (!isInitalized) + static std::set<BasicString, LessFilename> exceptions; + if (exceptions.empty()) { - 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")); + exceptions.insert(Zstr("exe")); + exceptions.insert(Zstr("lnk")); + exceptions.insert(Zstr("ico")); + exceptions.insert(Zstr("ani")); + exceptions.insert(Zstr("cur")); + exceptions.insert(Zstr("url")); + exceptions.insert(Zstr("msc")); + exceptions.insert(Zstr("scr")); } return exceptions.find(extension) != exceptions.end(); } #endif -} -//################################################################################################################################################ +//################################################################################################################################################ class IconBuffer::IconHolder //handle HICON/GdkPixbuf ownership WITHOUT ref-counting to allow thread-safe usage (in contrast to wxIcon) { public: @@ -139,7 +133,7 @@ const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be suffici 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 + if (::SHGetFileInfo(Zstr("dummy"), //Windows Seven doesn't like this parameter to be an empty string FILE_ATTRIBUTE_DIRECTORY, &fileInfo, sizeof(fileInfo), @@ -152,14 +146,14 @@ const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be suffici } #elif defined FFS_LINUX - folderIcon = getAssociatedIcon(DefaultStr("/usr/")).toWxIcon(); //all directories will look like "/usr/" + folderIcon = getAssociatedIcon(Zstr("/usr/")).toWxIcon(); //all directories will look like "/usr/" #endif } return folderIcon; } -IconBuffer::IconHolder IconBuffer::getAssociatedIcon(const Zstring& filename) +IconBuffer::IconHolder IconBuffer::getAssociatedIcon(const BasicString& filename) { #ifdef FFS_WIN //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName" @@ -231,15 +225,14 @@ IconBuffer::IconHolder IconBuffer::getAssociatedIcon(const Zstring& filename) #endif } - #ifdef FFS_WIN -IconBuffer::IconHolder IconBuffer::getAssociatedIconByExt(const Zstring& extension) +IconBuffer::IconHolder IconBuffer::getAssociatedIconByExt(const BasicString& extension) { SHFILEINFO fileInfo; fileInfo.hIcon = 0; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! //no read-access to disk! determine icon by extension - ::SHGetFileInfo((Zstring(DefaultStr("dummy.")) + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name + ::SHGetFileInfo((Zstr("dummy.") + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name FILE_ATTRIBUTE_NORMAL, &fileInfo, sizeof(fileInfo), @@ -250,12 +243,6 @@ IconBuffer::IconHolder IconBuffer::getAssociatedIconByExt(const Zstring& extensi #endif -//--------------------------------------------------------------------------------------------------- -typedef std::vector<DefaultChar> BasicString; //simple thread safe string class: std::vector is guaranteed to not use reference counting, Effective STL, item 13 -//avoid reference-counted objects as shared data: NOT THREADSAFE!!! (implicitly shared variables: ref-count + c-string) -//--------------------------------------------------------------------------------------------------- - - class IconBuffer::WorkerThread { public: @@ -308,7 +295,7 @@ void IconBuffer::WorkerThread::setWorkload(const std::vector<Zstring>& load) //( shared.workload.clear(); for (std::vector<Zstring>::const_iterator i = load.begin(); i != load.end(); ++i) - shared.workload.push_back(FileName(i->c_str(), i->c_str() + i->length() + 1)); //make DEEP COPY from Zstring (include null-termination)! + shared.workload.push_back(FileName(i->c_str())); //make DEEP COPY from Zstring } shared.condition.notify_one(); @@ -344,20 +331,20 @@ void IconBuffer::WorkerThread::doWork() //do work: get the file icon. while (true) { - Zstring fileName; + BasicString fileName; { boost::lock_guard<boost::mutex> dummy(shared.mutex); if (shared.workload.empty()) break; //enter waiting state - fileName = &shared.workload.back()[0]; //deep copy (includes NULL-termination) + fileName = shared.workload.back(); //deep copy shared.workload.pop_back(); } - if (iconBuffer.requestFileIcon(fileName)) //thread safety: Zstring okay, won't be reference-counted in requestIcon() + if (iconBuffer.requestFileIcon(fileName.c_str())) //thread safety: Zstring okay, won't be reference-counted in requestIcon() continue; //icon already in buffer: skip #ifdef FFS_WIN - const Zstring extension = getFileExtension(fileName); //thread-safe: no sharing! + const BasicString extension = getFileExtension(fileName); //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 { const IconHolder newIcon = IconBuffer::getAssociatedIcon(fileName); @@ -377,8 +364,8 @@ void IconBuffer::WorkerThread::doWork() //--------------------------------------------------------------------------------------------------- -class IconBuffer::IconDB : public std::map<Zstring, IconBuffer::IconHolder> {}; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure!!! (== don't copy instances between threads) -class IconBuffer::IconDbSequence : public std::queue<Zstring> {}; //entryName +class IconBuffer::IconDB : public std::map<BasicString, IconBuffer::IconHolder> {}; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure! +class IconBuffer::IconDbSequence : public std::queue<BasicString> {}; //entryName //--------------------------------------------------------------------------------------------------- @@ -405,10 +392,11 @@ bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon) #ifdef FFS_WIN //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension - const Zstring extension = getFileExtension(fileName); - IconDB::const_iterator i = buffer->find(isPriceyExtension(extension) ? fileName : extension); + const BasicString extension = getFileExtension(fileName.c_str()); + const BasicString searchString = isPriceyExtension(extension) ? fileName.c_str() : extension.c_str(); + IconDB::const_iterator i = buffer->find(searchString); #elif defined FFS_LINUX - IconDB::const_iterator i = buffer->find(fileName); + IconDB::const_iterator i = buffer->find(fileName.c_str()); #endif if (i == buffer->end()) @@ -427,17 +415,14 @@ void IconBuffer::setWorkload(const std::vector<Zstring>& load) } -void IconBuffer::insertIntoBuffer(const DefaultChar* entryName, const IconHolder& icon) //called by worker thread +void IconBuffer::insertIntoBuffer(const BasicString& entryName, const IconHolder& icon) //called by worker thread { boost::lock_guard<boost::mutex> dummy(lockIconDB); - //thread safety, ref-counting: (implicitly) make deep copy! - const Zstring fileNameZ = entryName; - - const std::pair<IconDB::iterator, bool> rc = buffer->insert(std::make_pair(fileNameZ, icon)); //thread saftey: icon uses ref-counting! But is NOT shared with main thread! - + //thread saftey: icon uses ref-counting! But is NOT shared with main thread! + const std::pair<IconDB::iterator, bool> rc = buffer->insert(std::make_pair(entryName, icon)); if (rc.second) //if insertion took place - bufSequence->push(fileNameZ); //note: sharing Zstring with IconDB!!! + bufSequence->push(entryName); //note: sharing Zstring with IconDB!!! assert(buffer->size() == bufSequence->size()); diff --git a/library/icon_buffer.h b/library/icon_buffer.h index 9dc1ee55..3e021445 100644 --- a/library/icon_buffer.h +++ b/library/icon_buffer.h @@ -11,7 +11,7 @@ #include "../shared/zstring.h" #include <memory> #include <wx/icon.h> -#include <boost/thread/mutex.hpp> +#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp> namespace ffs3 @@ -42,16 +42,26 @@ private: class IconHolder; class IconDbSequence; +//--------------------------------------------------------------------------------------------------- +typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class +//avoid reference-counted objects for shared data: NOT THREADSAFE!!! (implicitly shared variable: ref-count) +//--------------------------------------------------------------------------------------------------- + //methods used by worker thread - void insertIntoBuffer(const DefaultChar* entryName, const IconHolder& icon); + void insertIntoBuffer(const BasicString& entryName, const IconHolder& icon); + + static IconHolder getAssociatedIcon(const BasicString& filename); + static IconHolder getAssociatedIconByExt(const BasicString& extension); - static IconHolder getAssociatedIcon(const Zstring& filename); - static IconHolder getAssociatedIconByExt(const Zstring& extension); +#ifdef FFS_WIN +static BasicString getFileExtension(const BasicString& filename); +static bool isPriceyExtension(const BasicString& extension); +#endif //---------------------- Shared Data ------------------------- boost::mutex lockIconDB; std::auto_ptr<IconDB> buffer; //use synchronisation when accessing this! - std::auto_ptr<IconDbSequence> bufSequence; //save sequence of buffer entry to delete oldest elements (implicitly shared by sharing Zstring with IconDB!!!) + std::auto_ptr<IconDbSequence> bufSequence; //save sequence of buffer entry to delete oldest elements //------------------------------------------------------------ class WorkerThread; diff --git a/library/process_xml.cpp b/library/process_xml.cpp index e81fb3f9..c7597247 100644 --- a/library/process_xml.cpp +++ b/library/process_xml.cpp @@ -415,9 +415,6 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg //try to read program language setting readXmlElementLogging("Language", global, outputCfg.programLanguage); - //ignore +/- 1 hour due to DST change - readXmlElementLogging("IgnoreOneHourDifference", global, outputCfg.ignoreOneHourDiff); - //copy locked files using VSS readXmlElementLogging("CopyLockedFiles", global, outputCfg.copyLockedFiles); @@ -465,6 +462,11 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg readXmlElementLogging("RespectCaseOnSearch", mainWindow, outputCfg.gui.textSearchRespectCase); + size_t folderPairMax = 0; + readXmlElementLogging("FolderPairsMax", mainWindow, folderPairMax); + outputCfg.gui.addFolderPairCountMax = std::max(static_cast<size_t>(2), folderPairMax) - 1; //map folderPairMax to additionalFolderPairMax + + //########################################################### //read column attributes readXmlAttributeLogging("AutoAdjust", TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").ToElement(), outputCfg.gui.autoAdjustColumnsLeft); @@ -824,9 +826,6 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD //program language addXmlElement("Language", inputCfg.programLanguage, global); - //ignore +/- 1 hour due to DST change - addXmlElement("IgnoreOneHourDifference", inputCfg.ignoreOneHourDiff, global); - //copy locked files using VSS addXmlElement("CopyLockedFiles", inputCfg.copyLockedFiles, global); @@ -888,6 +887,9 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD addXmlElement("RespectCaseOnSearch", inputCfg.gui.textSearchRespectCase, mainWindow); + addXmlElement("FolderPairsMax", inputCfg.gui.addFolderPairCountMax + 1 /*add main pair*/, mainWindow); + + //write column attributes TiXmlElement* leftColumn = new TiXmlElement("LeftColumns"); mainWindow->LinkEndChild(leftColumn); diff --git a/library/process_xml.h b/library/process_xml.h index 22465739..24a2fe9b 100644 --- a/library/process_xml.h +++ b/library/process_xml.h @@ -117,14 +117,12 @@ struct XmlGlobalSettings //Shared (GUI/BATCH) settings XmlGlobalSettings() : programLanguage(retrieveSystemLanguage()), - ignoreOneHourDiff(false), copyLockedFiles(true), copyFilePermissions(false), fileTimeTolerance(2), //default 2s: FAT vs NTFS verifyFileCopy(false) {} int programLanguage; - bool ignoreOneHourDiff; //ignore +/- 1 hour due to DST change bool copyLockedFiles; //VSS usage bool copyFilePermissions; @@ -157,6 +155,7 @@ struct XmlGlobalSettings #endif showFileIconsLeft(true), showFileIconsRight(true), + addFolderPairCountMax(5), lastUpdateCheck(0) { //default external apps will be translated "on the fly"!!! @@ -204,6 +203,7 @@ struct XmlGlobalSettings bool showFileIconsLeft; bool showFileIconsRight; + size_t addFolderPairCountMax; long lastUpdateCheck; //time of last update check } gui; diff --git a/library/status_handler.h b/library/status_handler.h index a1226c54..c15a80ba 100644 --- a/library/status_handler.h +++ b/library/status_handler.h @@ -8,8 +8,7 @@ #define STATUSHANDLER_H_INCLUDED #include <wx/longlong.h> - -class Zstring; +#include "../shared/zstring.h" 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 @@ -53,9 +52,10 @@ public: //these methods have to be implemented in the derived classes to handle error and status information virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on - virtual void updateStatusText(const Zstring& text) = 0; virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) = 0; //called periodically after data was processed + virtual void reportInfo(const Zstring& text) = 0; + //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events virtual void forceUiRefresh() = 0; diff --git a/resource.rc b/resource.rc index 4abdfbaa..ef013684 100644 --- a/resource.rc +++ b/resource.rc @@ -1,27 +1,29 @@ #define IDR_VERSION1 1 +#include "Winver.h" #include "wx/msw/wx.rc" #include "version/version.rc" A_PROGRAM_ICON ICON DISCARDABLE "library/FreeFileSync.ico" -B_BATCH_ICON ICON DISCARDABLE "library/Batch.ico" +B_BATCH_ICON ICON DISCARDABLE "library/Batch.ico" C_SYNC_DB_ICON ICON DISCARDABLE "library/SyncDB.ico" -IDR_VERSION1 VERSIONINFO -FILEVERSION VER_FREEFILESYNC +IDR_VERSION1 VERSIONINFO +FILEVERSION VER_FREEFILESYNC PRODUCTVERSION VER_FREEFILESYNC -FILEOS 0x00000004 -FILETYPE 0x00000001 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "FFFF04B0" BEGIN - VALUE "ProductVersion", VER_FREEFILESYNC_STR VALUE "FileDescription", "FreeFileSync - Open Source Synchronization Software\0" - VALUE "LegalCopyright", "(c) 2008 - 2010 ZenJu\0" - VALUE "ProductName", "FreeFileSync\0" + VALUE "FileVersion", VER_FREEFILESYNC_STR + VALUE "ProductName", "FreeFileSync\0" + VALUE "ProductVersion", VER_FREEFILESYNC_STR + VALUE "LegalCopyright", "(c) 2008 - 2010 ZenJu\0" END END BLOCK "VarFileInfo" @@ -29,4 +31,3 @@ BEGIN VALUE "Translation", 0xFFFF, 0x04B0 END END - diff --git a/shared/IFileOperation/file_op.cpp b/shared/IFileOperation/file_op.cpp index f37a2e66..6180a561 100644 --- a/shared/IFileOperation/file_op.cpp +++ b/shared/IFileOperation/file_op.cpp @@ -7,37 +7,31 @@ #include "file_op.h" #include "../com_ptr.h" #include "../com_error.h" +#include "../c_dll.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 <comdef.h> #include <algorithm> #include <string> #include <cstdio> -#include <comdef.h> - +#define WIN32_LEAN_AND_MEAN +#include "windows.h" -void writeString(const std::wstring& input, wchar_t* output, size_t outputBufferLen) -{ - const size_t newSize = min(input.length() + 1, outputBufferLen); //including null-termination - memcpy(output, input.c_str(), newSize * sizeof(wchar_t)); - output[newSize-1] = 0; //if output buffer is too small... -} +using namespace c_dll; -namespace FileOp +namespace fileop { std::wstring lastErrorMessage; } -bool FileOp::moveToRecycleBin(const wchar_t* fileNames[], +bool fileop::moveToRecycleBin(const wchar_t* fileNames[], size_t fileNo) //size of fileNames array { - using Util::ComPtr; - using Util::generateErrorMsg; + using util::ComPtr; + using util::generateErrorMsg; HRESULT hr; // Create the IFileOperation interface @@ -117,11 +111,11 @@ bool FileOp::moveToRecycleBin(const wchar_t* fileNames[], } -bool FileOp::copyFile(const wchar_t* sourceFile, +bool fileop::copyFile(const wchar_t* sourceFile, const wchar_t* targetFile) { - using Util::ComPtr; - using Util::generateErrorMsg; + using util::ComPtr; + using util::generateErrorMsg; HRESULT hr; @@ -223,7 +217,7 @@ bool FileOp::copyFile(const wchar_t* sourceFile, //if any of the functions above returns 'false', this message returns last error -void FileOp::getLastError(wchar_t* errorMessage, size_t errorBufferLen) +void fileop::getLastError(wchar_t* errorMessage, size_t errorBufferLen) { writeString(lastErrorMessage, errorMessage, errorBufferLen); } diff --git a/shared/IFileOperation/file_op.h b/shared/IFileOperation/file_op.h index 8fa6a75b..97c75747 100644 --- a/shared/IFileOperation/file_op.h +++ b/shared/IFileOperation/file_op.h @@ -14,7 +14,7 @@ #endif -namespace FileOp +namespace fileop { //COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize @@ -32,8 +32,8 @@ void getLastError(wchar_t* errorMessage, size_t errorBufferLen); //function typedefs -typedef bool (*MoveToRecycleBinFct)(const wchar_t* fileNames[], size_t fileNo); -typedef bool (*CopyFileFct)(const wchar_t* sourceFile, const wchar_t* targetFile); +typedef bool (*MoveToRecycleBinFct)(const wchar_t* fileNames[], size_t fileNo); +typedef bool (*CopyFileFct)(const wchar_t* sourceFile, const wchar_t* targetFile); typedef void (*GetLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen); //function names (use const pointers to ensure internal linkage) diff --git a/shared/ShadowCopy/shadow.cpp b/shared/ShadowCopy/shadow.cpp index 2e739146..a5c280e8 100644 --- a/shared/ShadowCopy/shadow.cpp +++ b/shared/ShadowCopy/shadow.cpp @@ -5,11 +5,15 @@ // ************************************************************************** // #include "shadow.h" +#include <algorithm> +#include <string> +#include <comdef.h> +#include "../com_ptr.h" +#include "../com_error.h" +#include "../c_dll.h" #define WIN32_LEAN_AND_MEAN #include "windows.h" -#include "../com_ptr.h" -#include "../com_error.h" #ifdef USE_SHADOW_XP #include "xp/inc/vss.h" @@ -24,41 +28,32 @@ adapt! #endif -#include <algorithm> -#include <string> -#include <cstdio> -#include <comdef.h> +using namespace c_dll; -//typedef GUID VSS_ID; - -void writeString(const wchar_t* input, wchar_t* output, unsigned int outputBufferLen) +namespace { - 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... -} - +typedef HandleProvider<shadow::ShadowHandle, util::ComPtr<IVssBackupComponents> > HandleShadowMap; void writeErrorMsg(const wchar_t* input, HRESULT hr, wchar_t* output, unsigned int outputBufferLen) { - writeString(Util::generateErrorMsg(input, hr).c_str(), output, outputBufferLen); + writeString(util::generateErrorMsg(input, hr).c_str(), output, outputBufferLen); +} } - bool shadow::createShadowCopy(const wchar_t* volumeName, wchar_t* shadowVolName, unsigned int shadowBufferLen, - void** backupHandle, + ShadowHandle* handle, wchar_t* errorMessage, unsigned int errorBufferLen) { - using Util::ComPtr; - using Util::generateErrorMsg; + using util::ComPtr; + using util::generateErrorMsg; //MessageBox(0, L"backup err", L"", 0); */ - *backupHandle = NULL; + *handle = 0; HRESULT hr = NULL; ComPtr<IVssBackupComponents> backupComp; @@ -171,14 +166,13 @@ bool shadow::createShadowCopy(const wchar_t* volumeName, VssFreeSnapshotProperties(&props); - *backupHandle = backupComp.release(); //release ownership + *handle = HandleShadowMap::instance().insert(backupComp); return true; } -void shadow::releaseShadowCopy(void* backupHandle) +void shadow::releaseShadowCopy(ShadowHandle handle) { - if (backupHandle != NULL) - static_cast<IVssBackupComponents*>(backupHandle)->Release(); + HandleShadowMap::instance().remove(handle); } diff --git a/shared/ShadowCopy/shadow.h b/shared/ShadowCopy/shadow.h index a9120e8a..f1100284 100644 --- a/shared/ShadowCopy/shadow.h +++ b/shared/ShadowCopy/shadow.h @@ -18,32 +18,35 @@ namespace shadow { //COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize +typedef size_t ShadowHandle; //volumeName must end with "\", while shadowVolName does not end with "\" SHADOWDLL_API -bool createShadowCopy(const wchar_t* volumeName, - wchar_t* shadowVolName, - unsigned int shadowBufferLen, - void** backupHandle, - wchar_t* errorMessage, - unsigned int errorBufferLen); +bool createShadowCopy(const wchar_t* volumeName, //[in] + wchar_t* shadowVolName, //[out] + unsigned int shadowBufferLen, //[in] + ShadowHandle* handle, //[out] + wchar_t* errorMessage, //[out] + unsigned int errorBufferLen); //[in] //don't forget to release the backupHandle after shadow copy is not needed anymore! SHADOWDLL_API -void releaseShadowCopy(void* backupHandle); +void releaseShadowCopy(ShadowHandle handle); +//########################################################################################## + //function typedefs typedef bool (*CreateShadowCopyFct)(const wchar_t* volumeName, wchar_t* shadowVolName, unsigned int shadowBufferLen, - void** backupHandle, + ShadowHandle* handle, wchar_t* errorMessage, unsigned int errorBufferLen); -typedef void (*ReleaseShadowCopyFct)(void* backupHandle); +typedef void (*ReleaseShadowCopyFct)(ShadowHandle handle); //function names const char* const createShadowCopyFctName = "createShadowCopy"; diff --git a/shared/Taskbar_Seven/taskbar.cpp b/shared/Taskbar_Seven/taskbar.cpp index c9a2e7df..d1b1638c 100644 --- a/shared/Taskbar_Seven/taskbar.cpp +++ b/shared/Taskbar_Seven/taskbar.cpp @@ -11,69 +11,41 @@ #include <ShObjIdl.h> #include <map> -#include <string> +#include <string> #include <comdef.h> #include "../com_error.h" +#include "../com_ptr.h" +#include "../c_dll.h" -namespace -{ -void writeString(const std::wstring& input, wchar_t* output, size_t outputBufferLen) -{ - const size_t newSize = min(input.length() + 1, outputBufferLen); //including null-termination - memcpy(output, input.c_str(), newSize * sizeof(wchar_t)); - output[newSize-1] = 0; //if output buffer is too small... -} +using namespace util; +using namespace c_dll; -using Util::generateErrorMsg; -using TaskbarSeven::TBHandle; -typedef std::map<TBHandle, ITaskbarList3*> TaskBarHandleMap; - -TaskbarSeven::TBHandle generateHandle() +namespace { - static TBHandle handle = 0; - return ++handle; //don't return 0! 0 is reserved for indicating failure -} - -TaskBarHandleMap taskBarHandles; - std::wstring lastErrorMessage; -} -//################################################################################################## -TaskbarSeven::TBHandle TaskbarSeven::init() //call on app initializaiton; returns handle +ComPtr<ITaskbarList3> getInstance() { - ITaskbarList3* pto = NULL; - HRESULT hr = CoCreateInstance(CLSID_TaskbarList, - NULL, - CLSCTX_ALL, - IID_PPV_ARGS(&pto)); - if (FAILED(hr)) + static ComPtr<ITaskbarList3> taskbarlist; + if (!taskbarlist) { - lastErrorMessage = generateErrorMsg(L"Error calling \"CoCreateInstance\".", hr); - return 0; + HRESULT hr = CoCreateInstance(CLSID_TaskbarList, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(taskbarlist.init())); + if (FAILED(hr)) + lastErrorMessage = generateErrorMsg(L"Error calling \"CoCreateInstance\".", hr); } - TBHandle newHandle = ::generateHandle(); - taskBarHandles[newHandle] = pto; - return newHandle; + return taskbarlist; } - -void TaskbarSeven::release(TBHandle handle) //release handle on app exit -{ - TaskBarHandleMap::const_iterator iter = taskBarHandles.find(handle); - if (iter != taskBarHandles.end()) - { - if (iter->second != NULL) - iter->second->Release(); - taskBarHandles.erase(iter); - } } +//################################################################################################## -bool TaskbarSeven::setStatus(TBHandle handle, - void* hwnd, //HWND: window assciated to the taskbar icon +bool tbseven::setStatus(void* hwnd, //HWND: window assciated to the taskbar icon TaskBarStatus status) { TBPFLAG flag = TBPF_NORMAL; @@ -96,45 +68,45 @@ bool TaskbarSeven::setStatus(TBHandle handle, break; } - ITaskbarList3* pto = taskBarHandles[handle]; - if (pto) + ComPtr<ITaskbarList3> taskbarlist = getInstance(); + if (!taskbarlist) //error msg already set + return false; + + HRESULT hr = taskbarlist->SetProgressState(static_cast<HWND>(hwnd), //[in] HWND hwnd, + flag); //[in] TBPFLAG tbpFlags + if (FAILED(hr)) { - HRESULT hr = pto->SetProgressState(static_cast<HWND>(hwnd), //[in] HWND hwnd, - flag); //[in] TBPFLAG tbpFlags - if (FAILED(hr)) - { - lastErrorMessage = generateErrorMsg(L"Error calling \"SetProgressState\".", hr); - return false; - } + lastErrorMessage = generateErrorMsg(L"Error calling \"SetProgressState\".", hr); + return false; } + return true; } -bool TaskbarSeven::setProgress(TBHandle handle, - void* hwnd, //HWND: window assciated to the taskbar icon +bool tbseven::setProgress(void* hwnd, //HWND: window assciated to the taskbar icon size_t current, size_t total) { - ITaskbarList3* pto = taskBarHandles[handle]; - - if (pto) + ComPtr<ITaskbarList3> taskbarlist = getInstance(); + if (!taskbarlist) //error msg already set + return false; + + HRESULT hr = taskbarlist->SetProgressValue( + static_cast<HWND>(hwnd), //[in] HWND hwnd, + current, //[in] ULONGLONG ullCompleted, + total); //[in] ULONGLONG ullTotal + if (FAILED(hr)) { - HRESULT hr = pto->SetProgressValue( - static_cast<HWND>(hwnd), //[in] HWND hwnd, - current, //[in] ULONGLONG ullCompleted, - total); //[in] ULONGLONG ullTotal - if (FAILED(hr)) - { - lastErrorMessage = generateErrorMsg(L"Error calling \"SetProgressValue\".", hr); - return false; - } + lastErrorMessage = generateErrorMsg(L"Error calling \"SetProgressValue\".", hr); + return false; } + return true; } -void TaskbarSeven::getLastError(wchar_t* errorMessage, size_t errorBufferLen) +void tbseven::getLastError(wchar_t* errorMessage, size_t errorBufferLen) { writeString(lastErrorMessage, errorMessage, errorBufferLen); } diff --git a/shared/Taskbar_Seven/taskbar.h b/shared/Taskbar_Seven/taskbar.h index 3b7abc51..34e122c0 100644 --- a/shared/Taskbar_Seven/taskbar.h +++ b/shared/Taskbar_Seven/taskbar.h @@ -14,7 +14,7 @@ #endif -namespace TaskbarSeven +namespace tbseven { enum TaskBarStatus { @@ -25,25 +25,16 @@ enum TaskBarStatus STATUS_PAUSED }; -typedef size_t TBHandle; - //COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize -DLL_FUNCTION_DECLARATION -TBHandle init(); //returns handle; 0 on failure - -DLL_FUNCTION_DECLARATION -void release(TBHandle handle); //release taskbar handle DLL_FUNCTION_DECLARATION -bool setStatus(TBHandle handle, - void* hwnd, //HWND: window assciated to the taskbar icon +bool setStatus(void* hwnd, //HWND: window assciated to the taskbar icon TaskBarStatus status); DLL_FUNCTION_DECLARATION -bool setProgress(TBHandle handle, - void* hwnd, //HWND: window assciated to the taskbar icon +bool setProgress(void* hwnd, //HWND: window assciated to the taskbar icon size_t current, size_t total); @@ -53,18 +44,14 @@ void getLastError(wchar_t* errorMessage, size_t errorBufferLen); //function typedefs -typedef TBHandle (*initFct)(); -typedef void (*releaseFct)(TBHandle handle); -typedef bool (*setStatusFct)(TBHandle handle, void* hwnd, TaskBarStatus status); -typedef bool (*setProgressFct)(TBHandle handle, void* hwnd, size_t current, size_t total); -typedef void (*getLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen); +typedef bool (*SetStatusFct)(void* hwnd, TaskBarStatus status); +typedef bool (*SetProgressFct)(void* hwnd, size_t current, size_t total); +typedef void (*GetLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen); //function names (use const pointers to ensure internal linkage) -const char* const initFctName = "init"; -const char* const releaseFctName = "release"; const char* const setStatusFctName = "setStatus"; const char* const setProgressFctName = "setProgress"; const char* const getLastErrorFctName = "getLastError"; } -#endif //TASKBAR_SEVEN_DLL_H
\ No newline at end of file +#endif //TASKBAR_SEVEN_DLL_H diff --git a/shared/app_main.cpp b/shared/app_main.cpp index 7225ba62..3d42212a 100644 --- a/shared/app_main.cpp +++ b/shared/app_main.cpp @@ -11,7 +11,7 @@ using namespace ffs3; -bool AppMainWindow::mainWndAct = false; +bool AppMainWindow::mainWndActive = false; void ffs3::AppMainWindow::setMainWindow(wxWindow* window) @@ -19,11 +19,11 @@ void ffs3::AppMainWindow::setMainWindow(wxWindow* window) wxTheApp->SetTopWindow(window); wxTheApp->SetExitOnFrameDelete(true); - mainWndAct = true; + mainWndActive = true; } bool AppMainWindow::mainWindowWasSet() { - return mainWndAct; + return mainWndActive; } diff --git a/shared/app_main.h b/shared/app_main.h index d0b76122..7e4fa7e7 100644 --- a/shared/app_main.h +++ b/shared/app_main.h @@ -19,7 +19,7 @@ public: static bool mainWindowWasSet(); private: - static bool mainWndAct; + static bool mainWndActive; }; } diff --git a/shared/c_dll.h b/shared/c_dll.h new file mode 100644 index 00000000..4d485893 --- /dev/null +++ b/shared/c_dll.h @@ -0,0 +1,132 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// +#ifndef C_DLL_HEADER +#define C_DLL_HEADER + +#include <string> +#include <map> +#undef min +#include <algorithm> + + +namespace c_dll +{ +void writeString(const std::wstring& input, wchar_t* output, size_t outputLen); + + +//Convert handles to objects and vice versa +template <class S, class T> //T: prefer managed object to ensure cleanup if remove() is not called +class HandleProvider +{ +public: + static HandleProvider& instance(); + S insert(T object); + void remove(S handle); + T& retrieve(S handle); //return default-constructed object if not found + +private: + HandleProvider() {} + HandleProvider(const HandleProvider&); + HandleProvider& operator=(const HandleProvider&); + S generate(); + + std::map<S, T> handleMap; +}; +/* +Example: + typedef HandleProvider<TBHandle, ComPtr<ITaskbarList3> > HandleTaskbarMap; + HandleTaskbarMap::instance().insert(xyz); +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//########################## inline implementation ############################# +inline +void writeString(const std::wstring& input, wchar_t* output, size_t outputLen) +{ + if (outputLen > 0) + { + const size_t maxSize = std::min(input.length(), outputLen - 1); + std::copy(input.begin(), input.begin() + maxSize, output); + output[maxSize] = 0; + } +} + + +template <class S, class T> +inline +HandleProvider<S, T>& HandleProvider<S, T>::instance() +{ + static HandleProvider inst; + return inst; +} + + +//convert handles to objects and vice versa +template <class S, class T> +inline +S HandleProvider<S, T>::insert(T object) +{ + S newHandle = generate(); + handleMap.insert(std::make_pair(newHandle, object)); + return newHandle; +} + + +template <class S, class T> +inline +void HandleProvider<S, T>::remove(S handle) +{ + handleMap.erase(handle); +} + + +template <class S, class T> +inline +T& HandleProvider<S, T>::retrieve(S handle) //return default-constructed object if not found +{ + return handleMap[handle]; +} + + +template <class S, class T> +inline +S HandleProvider<S, T>::generate() +{ + static S handle = 0; + return ++handle; //don't return 0! 0 is reserved for indicating failure +} + + +} + +#endif //C_DLL_HEADER
\ No newline at end of file diff --git a/shared/check_exist.cpp b/shared/check_exist.cpp index fcb865fd..8bc629b5 100644 --- a/shared/check_exist.cpp +++ b/shared/check_exist.cpp @@ -1,34 +1,42 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// #include "check_exist.h" #include "file_handling.h" -#include <boost/thread.hpp> +#include "boost_thread_wrap.h" //include <boost/thread.hpp> #include <boost/shared_ptr.hpp> +/* #ifdef __MINGW32__ //oh well, nothing is for free... //https://svn.boost.org/trac/boost/ticket/4258 -#warning fix this issue at some time... -extern "C" void tss_cleanup_implemented() {} +extern "C" void tss_cleanup_implemented() {}; #endif - +*/ namespace { +typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class + template <bool (*testExist)(const Zstring&)> class ExistenceChecker { public: - ExistenceChecker(const Zstring& filename, const boost::shared_ptr<bool>& isExisting) : - filename_(filename.c_str()), //deep copy: worker thread may run longer than main! avoid shared data - isExisting_(isExisting) {} //not accessed during thread run + ExistenceChecker(const BasicString& filename, const boost::shared_ptr<bool>& isExisting) : + filename_(filename), //deep copy: worker thread may run longer than main! avoid shared data + isExisting_(isExisting) {} //not accessed during thread run void operator()() { - *isExisting_ = testExist(filename_); //throw() + *isExisting_ = testExist(filename_.c_str()); //throw() } private: - const Zstring filename_; //no reference, lifetime not known + const BasicString filename_; //no referencing, 'cause lifetime not known! boost::shared_ptr<bool> isExisting_; }; @@ -40,8 +48,8 @@ util::ResultExist checkExistence(const Zstring& objName, size_t timeout) //timeo boost::shared_ptr<bool> isExisting(new bool(false)); - ExistenceChecker<fun> task(objName, isExisting); - boost::thread worker(task); + ExistenceChecker<fun> task(objName.c_str(), isExisting); + boost::thread worker(task); //note: task is copied => using thread safe string! if (worker.timed_join(boost::posix_time::milliseconds(timeout))) return *isExisting ? EXISTING_TRUE : EXISTING_FALSE; @@ -56,7 +64,7 @@ util::ResultExist checkExistence(const Zstring& objName, size_t timeout) //timeo #warning migrate this at some time... #endif /* - unfortunately packaged_task/future is not mature enough to be used... + unfortunately packaged_task/future is not mature enough to be used... boost::packaged_task<bool> pt(boost::bind(fun, objName.c_str())); //attention: Zstring is not thread-safe => make deep copy boost::unique_future<bool> fut = pt.get_future(); diff --git a/shared/com_error.h b/shared/com_error.h index ab365977..73551f6e 100644 --- a/shared/com_error.h +++ b/shared/com_error.h @@ -28,6 +28,9 @@ public: } private: + ComException(const ComException&); + ComException& operator=(const ComException&); + const std::wstring message_; const HRESULT hr_; }; diff --git a/shared/com_util.h b/shared/com_util.h index bda3c732..22e2075f 100644 --- a/shared/com_util.h +++ b/shared/com_util.h @@ -4,8 +4,8 @@ // * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // -#ifndef COM_UTILÎTY_HEADER -#define COM_UTILÎTY_HEADER +#ifndef COM_UTILITY_HEADER +#define COM_UTILITY_HEADER #include "com_ptr.h" #include <string> @@ -152,4 +152,4 @@ const BSTR Bstring::get() const } -#endif //COM_UTILÎTY_HEADER
\ No newline at end of file +#endif //COM_UTILITY_HEADER
\ No newline at end of file diff --git a/shared/custom_button.cpp b/shared/custom_button.cpp index fec3b4bb..7154814b 100644 --- a/shared/custom_button.cpp +++ b/shared/custom_button.cpp @@ -7,6 +7,8 @@ #include "custom_button.h" #include <wx/dcmemory.h> #include <wx/image.h> +#include <algorithm> + wxButtonWithImage::wxButtonWithImage(wxWindow *parent, wxWindowID id, diff --git a/shared/debug_new.cpp b/shared/debug_new.cpp index f5cd8368..0c0c8b52 100644 --- a/shared/debug_new.cpp +++ b/shared/debug_new.cpp @@ -5,15 +5,14 @@ // ************************************************************************** // #include "debug_new.h" -#include <wx/msw/wrapwin.h> //includes "windows.h" -#include "DbgHelp.h" -#pragma message("Warning! Include this header for error analysis builds only!") -#ifndef _MSC_VER -use in Visual C++ only! +#ifdef _MSC_VER +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "DbgHelp.h" //available for MSC only #endif +#ifdef _MSC_VER namespace { LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo) @@ -28,8 +27,8 @@ LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo) MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : NULL; ::MiniDumpWriteDump( - GetCurrentProcess(), //__in HANDLE hProcess, - GetCurrentProcessId(), //__in DWORD ProcessId, + ::GetCurrentProcess(), //__in HANDLE hProcess, + ::GetCurrentProcessId(), //__in DWORD ProcessId, hFile, //__in HANDLE hFile, MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -49,11 +48,13 @@ struct WriteDumpOnUnhandledException { ::SetUnhandledExceptionFilter(writeDumpOnException); } -} dummy; //ensure that a Dump is written for uncaught exceptions +} dummy; //ensure that a dump-file is written for uncaught exceptions } -void MemoryDump::writeMinidump() +void mem_check::writeMinidump() { writeDumpOnException(NULL); } + +#endif //_MSC_VER diff --git a/shared/debug_new.h b/shared/debug_new.h index c9c3dbf6..e96b1e48 100644 --- a/shared/debug_new.h +++ b/shared/debug_new.h @@ -12,15 +12,21 @@ #include <cstdlib> //malloc(), free() -/*all this header does is to globally overwrite "operator new" to give some more detailed error messages and write memory dumps +#ifndef _MSC_VER +#error currently for use with MSC only +#endif + +/*overwrite "operator new" to get more detailed error messages on bad_alloc, detect memory leaks and write memory dumps Usage: - - Include everywhere before any other file: $(ProjectDir)\shared\debug_new.h - For Minidumps: - - Compile "debug_new.cpp" - - Include library "Dbghelp.lib" - - Compile in Debug build (need Symbols and less restrictive Optimization) +- Include everywhere before any other file: $(ProjectDir)\shared\debug_new.h +For Minidumps: +- Compile "debug_new.cpp" +- Include library "Dbghelp.lib" +- Compile in Debug build (need Symbols and less restrictive Optimization) */ +namespace mem_check +{ class BadAllocDetailed : public std::bad_alloc { public: @@ -41,7 +47,7 @@ private: template <class T> static std::string numberToString(const T& number) //convert number to string the C++ way { - std::stringstream ss; + std::ostringstream ss; ss << number; return ss.str(); } @@ -50,46 +56,43 @@ private: }; #ifdef _MSC_VER -namespace MemoryDump -{ void writeMinidump(); -} #endif +} inline -void* operator new(size_t allocSize) +void* operator new(size_t size) { - void* newMem = ::malloc(allocSize); + void* newMem = ::malloc(size); if (!newMem) { #ifdef _MSC_VER - MemoryDump::writeMinidump(); + mem_check::writeMinidump(); #endif - throw BadAllocDetailed(allocSize); + throw mem_check::BadAllocDetailed(size); } return newMem; } inline -void* operator new[](size_t allocSize) +void operator delete(void* ptr) { - return operator new(allocSize); + ::free(ptr); } inline -void operator delete(void* memory) +void* operator new[](size_t size) { - ::free(memory); + return operator new(size); } inline -void operator delete[](void* memory) +void operator delete[](void* ptr) { - operator delete(memory); + operator delete(ptr); } #endif // DEBUGNEW_H_INCLUDED - diff --git a/shared/drag_n_drop.cpp b/shared/dir_name.cpp index c4fc98f6..40e840f5 100644 --- a/shared/drag_n_drop.cpp +++ b/shared/dir_name.cpp @@ -4,16 +4,17 @@ // * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // -#include "drag_n_drop.h" +#include "dir_name.h" #include <wx/dnd.h> #include <wx/window.h> -#include <wx/combobox.h> #include <wx/textctrl.h> -#include <wx/filepicker.h> #include <wx/filename.h> #include "file_handling.h" #include "string_conv.h" #include "check_exist.h" +#include "util.h" +#include "system_constants.h" +#include <wx/statbox.h> //define new event type @@ -41,9 +42,68 @@ public: const wxWindow* dropWindow_; }; + //############################################################################################################## +namespace +{ +void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, wxWindow& tooltipWnd, wxStaticBoxSizer* staticBox, size_t timeout) +{ + using namespace ffs3; + + const wxString dirFormatted = zToWx(getFormattedDirectoryName(wxToZ(dirname))); + + tooltipWnd.SetToolTip(dirFormatted); + + if (staticBox) + { + //change static box label only if there is a real difference to what is shown in wxTextCtrl anyway + wxString dirNormalized = dirname; + dirNormalized.Trim(true); + dirNormalized.Trim(false); + if (!dirNormalized.empty() && !dirNormalized.EndsWith(zToWx(common::FILE_NAME_SEPARATOR))) + dirNormalized += zToWx(common::FILE_NAME_SEPARATOR); + + staticBox->GetStaticBox()->SetLabel(dirNormalized == dirFormatted ? wxString(_("Drag && drop")) : dirFormatted); + } + if (dirPicker) + { + if (util::dirExists(wxToZ(dirFormatted), timeout) == util::EXISTING_TRUE) //potentially slow network access: wait 200ms at most + dirPicker->SetPath(dirFormatted); + } +} + +void setDirectoryName(const wxString& dirname, + wxTextCtrl* txtCtrl, + wxDirPickerCtrl* dirPicker, + wxWindow& tooltipWnd, + size_t timeout = 200) //pointers are optional +{ + if (txtCtrl) + txtCtrl->ChangeValue(dirname); + setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, NULL, timeout); +} + + +void setDirectoryName(const wxString& dirname, + wxComboBox* comboBox, + wxDirPickerCtrl* dirPicker, + wxWindow& tooltipWnd, + wxStaticBoxSizer& staticBox, + size_t timeout = 200) //pointers are optional +{ + if (comboBox) + { + comboBox->SetSelection(wxNOT_FOUND); + comboBox->SetValue(dirname); + } + setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, &staticBox, timeout); +} +} + + +//############################################################################################################## class WindowDropTarget : public wxFileDropTarget { public: @@ -70,35 +130,36 @@ private: }; - //############################################################################################################## - -using ffs3::DragDropOnMainDlg; - -DragDropOnMainDlg::DragDropOnMainDlg(wxWindow* dropWindow1, - wxWindow* dropWindow2, - wxDirPickerCtrl* dirPicker, - wxComboBox* dirName) : +using ffs3::DirectoryNameMainDlg; + +DirectoryNameMainDlg::DirectoryNameMainDlg( + wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName, + wxStaticBoxSizer* staticBox) : dropWindow1_(dropWindow1), dropWindow2_(dropWindow2), dirPicker_(dirPicker), - dirName_(dirName) + dirName_(dirName), + staticBox_(staticBox) { //prepare drag & drop dropWindow1->SetDropTarget(new WindowDropTarget(dropWindow1)); //takes ownership dropWindow2->SetDropTarget(new WindowDropTarget(dropWindow2)); //takes ownership //redirect drag & drop event back to this class - dropWindow1->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnMainDlg::OnFilesDropped), NULL, this); - dropWindow2->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnMainDlg::OnFilesDropped), NULL, this); + dropWindow1->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryNameMainDlg::OnFilesDropped), NULL, this); + dropWindow2->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryNameMainDlg::OnFilesDropped), NULL, this); //keep dirPicker and dirName synchronous - dirName-> Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DragDropOnMainDlg::OnWriteDirManually), NULL, this ); - dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DragDropOnMainDlg::OnDirSelected), NULL, this ); + dirName-> Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryNameMainDlg::OnWriteDirManually), NULL, this ); + dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryNameMainDlg::OnDirSelected), NULL, this ); } -void DragDropOnMainDlg::OnFilesDropped(FFSFileDropEvent& event) +void DirectoryNameMainDlg::OnFilesDropped(FFSFileDropEvent& event) { if (event.filesDropped_.empty()) return; @@ -110,52 +171,50 @@ void DragDropOnMainDlg::OnFilesDropped(FFSFileDropEvent& event) { wxString fileName = event.filesDropped_[0]; if (wxDirExists(fileName)) - { - dirName_->SetSelection(wxNOT_FOUND); - dirName_->SetValue(fileName); - dirPicker_->SetPath(fileName); - } + setDirectoryName(fileName, dirName_, dirPicker_, *dirName_, *staticBox_); else { fileName = wxFileName(fileName).GetPath(); if (wxDirExists(fileName)) - { - dirName_->SetSelection(wxNOT_FOUND); - dirName_->SetValue(fileName); - dirPicker_->SetPath(fileName); - } + setDirectoryName(fileName, dirName_, dirPicker_, *dirName_, *staticBox_); } } } } -void DragDropOnMainDlg::OnWriteDirManually(wxCommandEvent& event) +void DirectoryNameMainDlg::OnWriteDirManually(wxCommandEvent& event) { - const Zstring newDir = getFormattedDirectoryName(wxToZ(event.GetString())); - - if (util::dirExists(newDir, 100) == util::EXISTING_TRUE) //potentially slow network access: wait 100 ms at most - dirPicker_->SetPath(zToWx(newDir)); - + setDirectoryName(event.GetString(), NULL, dirPicker_, *dirName_, *staticBox_, 100); //potentially slow network access: wait 100 ms at most event.Skip(); } -void DragDropOnMainDlg::OnDirSelected(wxFileDirPickerEvent& event) +void DirectoryNameMainDlg::OnDirSelected(wxFileDirPickerEvent& event) { const wxString newPath = event.GetPath(); - dirName_->SetSelection(wxNOT_FOUND); - dirName_->SetValue(newPath); + setDirectoryName(newPath, dirName_, NULL, *dirName_, *staticBox_); event.Skip(); } -//############################################################################################################## + +Zstring DirectoryNameMainDlg::getName() const +{ + return wxToZ(dirName_->GetValue()); +} -using ffs3::DragDropOnDlg; +void DirectoryNameMainDlg::setName(const Zstring& dirname) +{ + setDirectoryName(zToWx(dirname), dirName_, dirPicker_, *dirName_, *staticBox_); +} + + +//############################################################################################################## +using ffs3::DirectoryName; -DragDropOnDlg::DragDropOnDlg(wxWindow* dropWindow, +DirectoryName::DirectoryName(wxWindow* dropWindow, wxDirPickerCtrl* dirPicker, wxTextCtrl* dirName) : dropWindow_(dropWindow), @@ -166,15 +225,15 @@ DragDropOnDlg::DragDropOnDlg(wxWindow* dropWindow, dropWindow->SetDropTarget(new WindowDropTarget(dropWindow)); //takes ownership //redirect drag & drop event back to this class - dropWindow->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DragDropOnDlg::OnFilesDropped), NULL, this); + dropWindow->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); //keep dirPicker and dirName synchronous - dirName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DragDropOnDlg::OnWriteDirManually ), NULL, this ); - dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( DragDropOnDlg::OnDirSelected ), NULL, this ); + dirName->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually ), NULL, this ); + dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( DirectoryName::OnDirSelected ), NULL, this ); } -void DragDropOnDlg::OnFilesDropped(FFSFileDropEvent& event) +void DirectoryName::OnFilesDropped(FFSFileDropEvent& event) { if (event.filesDropped_.empty()) return; @@ -183,37 +242,40 @@ void DragDropOnDlg::OnFilesDropped(FFSFileDropEvent& event) { wxString fileName = event.filesDropped_[0]; if (wxDirExists(fileName)) - { - dirName_->SetValue(fileName); - dirPicker_->SetPath(fileName); - } + setDirectoryName(fileName, dirName_, dirPicker_, *dirName_); else { fileName = wxFileName(fileName).GetPath(); if (wxDirExists(fileName)) - { - dirName_->SetValue(fileName); - dirPicker_->SetPath(fileName); - } + setDirectoryName(fileName, dirName_, dirPicker_, *dirName_); } } } -void DragDropOnDlg::OnWriteDirManually(wxCommandEvent& event) +void DirectoryName::OnWriteDirManually(wxCommandEvent& event) { - const Zstring newDir = ffs3::getFormattedDirectoryName(wxToZ(event.GetString())); - if (util::dirExists(newDir, 100) == util::EXISTING_TRUE) //potentially slow network access: wait 100 ms at most - dirPicker_->SetPath(zToWx(newDir)); - + setDirectoryName(event.GetString(), NULL, dirPicker_, *dirName_, 100); //potentially slow network access: wait 100 ms at most event.Skip(); } -void DragDropOnDlg::OnDirSelected(wxFileDirPickerEvent& event) +void DirectoryName::OnDirSelected(wxFileDirPickerEvent& event) { const wxString newPath = event.GetPath(); - dirName_->SetValue(newPath); + setDirectoryName(newPath, dirName_, NULL, *dirName_); event.Skip(); } + + +Zstring DirectoryName::getName() const +{ + return wxToZ(dirName_->GetValue()); +} + + +void DirectoryName::setName(const Zstring& dirname) +{ + setDirectoryName(zToWx(dirname), dirName_, dirPicker_, *dirName_); +} diff --git a/shared/drag_n_drop.h b/shared/dir_name.h index 88bb68c4..163caaad 100644 --- a/shared/drag_n_drop.h +++ b/shared/dir_name.h @@ -9,30 +9,33 @@ #include <wx/event.h> #include <vector> +#include <wx/sizer.h> +#include <wx/filepicker.h> +#include <wx/combobox.h> +#include "zstring.h" + -class wxWindow; -class wxDirPickerCtrl; -class wxComboBox; -class wxTextCtrl; -class wxString; class FFSFileDropEvent; class wxCommandEvent; class wxFileDirPickerEvent; - namespace ffs3 { -//add drag and drop functionality, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl +//handle drag and drop, tooltip, label and manual input, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl -class DragDropOnMainDlg : private wxEvtHandler +class DirectoryNameMainDlg : private wxEvtHandler { public: - DragDropOnMainDlg(wxWindow* dropWindow1, - wxWindow* dropWindow2, - wxDirPickerCtrl* dirPicker, - wxComboBox* dirName); + DirectoryNameMainDlg(wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName, + wxStaticBoxSizer* staticBox); + + virtual ~DirectoryNameMainDlg() {} - virtual ~DragDropOnMainDlg() {} + Zstring getName() const; + void setName(const Zstring& dirname); virtual bool AcceptDrop(const std::vector<wxString>& droppedFiles) = 0; //return true if drop should be processed @@ -41,20 +44,24 @@ private: void OnWriteDirManually(wxCommandEvent& event); void OnDirSelected(wxFileDirPickerEvent& event); - const wxWindow* dropWindow1_; - const wxWindow* dropWindow2_; - wxDirPickerCtrl* dirPicker_; - wxComboBox* dirName_; + const wxWindow* dropWindow1_; + const wxWindow* dropWindow2_; + wxDirPickerCtrl* dirPicker_; + wxComboBox* dirName_; + wxStaticBoxSizer* staticBox_; }; -class DragDropOnDlg: private wxEvtHandler +class DirectoryName: private wxEvtHandler { public: - DragDropOnDlg(wxWindow* dropWindow, + DirectoryName(wxWindow* dropWindow, wxDirPickerCtrl* dirPicker, wxTextCtrl* dirName); + Zstring getName() const; + void setName(const Zstring& dirname); + private: void OnFilesDropped(FFSFileDropEvent& event); void OnWriteDirManually(wxCommandEvent& event); diff --git a/shared/dll_loader.cpp b/shared/dll_loader.cpp index 6aa48fd7..61a5a2fb 100644 --- a/shared/dll_loader.cpp +++ b/shared/dll_loader.cpp @@ -11,7 +11,7 @@ namespace { -class DllHandler //dynamically load "kernel32.dll" +class DllHandler { public: static DllHandler& getInstance() @@ -20,12 +20,15 @@ public: return instance; } - HINSTANCE getHandle(const std::wstring& libraryName) + HMODULE getHandle(const std::wstring& libraryName) { HandleMap::const_iterator foundEntry = handles.find(libraryName); if (foundEntry == handles.end()) { - HINSTANCE newHandle = ::LoadLibrary(libraryName.c_str()); + if (libraryName.empty()) + return ::GetModuleHandle(NULL); //return handle to calling executable + + HMODULE newHandle = ::LoadLibrary(libraryName.c_str()); if (newHandle != NULL) handles.insert(std::make_pair(libraryName, newHandle)); @@ -37,6 +40,8 @@ public: private: DllHandler() {} + DllHandler(const DllHandler&); + DllHandler& operator=(const DllHandler&); ~DllHandler() { @@ -44,18 +49,43 @@ private: ::FreeLibrary(i->second); } - typedef std::map<std::wstring, HINSTANCE> HandleMap; + typedef std::map<std::wstring, HMODULE> HandleMap; HandleMap handles; //only valid handles here! }; } -void* util::loadSymbol(const std::wstring& libraryName, const std::string& functionName) +FARPROC util::loadSymbol(const std::wstring& libraryName, const std::string& functionName) { - const HINSTANCE libHandle = DllHandler::getInstance().getHandle(libraryName); + const HMODULE libHandle = DllHandler::getInstance().getHandle(libraryName); if (libHandle != NULL) - return reinterpret_cast<void*>(::GetProcAddress(libHandle, functionName.c_str())); + return ::GetProcAddress(libHandle, functionName.c_str()); else return NULL; } + + +std::string util::getResourceStream(const std::wstring& libraryName, size_t resourceId) +{ + std::string output; + const HMODULE module = DllHandler::getInstance().getHandle(libraryName); + if (module) + { + const HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA); + if (res != NULL) + { + const HGLOBAL resHandle = ::LoadResource(module, res); + if (resHandle != NULL) + { + const char* stream = static_cast<const char*>(::LockResource(resHandle)); + if (stream) + { + const DWORD streamSize = ::SizeofResource(module, res); + output.assign(stream, streamSize); + } + } + } + } + return output; +} diff --git a/shared/dll_loader.h b/shared/dll_loader.h index 86723c68..b3fa5218 100644 --- a/shared/dll_loader.h +++ b/shared/dll_loader.h @@ -8,16 +8,29 @@ #define DLLLOADER_H_INCLUDED #include <string> +#include <wx/msw/wrapwin.h> //includes "windows.h" + namespace util { -//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! :) +/* +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); +FunctionType getDllFun(const std::wstring& libraryName, const std::string& functionName); + +/* +extract binary resources from .exe/.dll: +-- resource.h -- +#define MY_BINARY_RESOURCE 1337 +-- resource.rc -- +MY_BINARY_RESOURCE RCDATA "filename.dat" +*/ +std::string getResourceStream(const std::wstring& libraryName, size_t resourceId); @@ -29,19 +42,14 @@ FunctionType loadDllFunction(const std::wstring& libraryName, const std::string& //---------------Inline Implementation--------------------------------------------------- -void* loadSymbol(const std::wstring& libraryName, const std::string& functionName); +FARPROC loadSymbol(const std::wstring& libraryName, const std::string& functionName); template <typename FunctionType> inline -FunctionType loadDllFunction(const std::wstring& libraryName, const std::string& functionName) +FunctionType getDllFun(const std::wstring& libraryName, const std::string& functionName) { return reinterpret_cast<FunctionType>(loadSymbol(libraryName, functionName)); } - -#ifndef FFS_WIN -use in windows build only! -#endif - } #endif // DLLLOADER_H_INCLUDED diff --git a/shared/dst_hack.cpp b/shared/dst_hack.cpp new file mode 100644 index 00000000..87ed6c2f --- /dev/null +++ b/shared/dst_hack.cpp @@ -0,0 +1,312 @@ +#include "dst_hack.h" +#include "system_constants.h" +#include <wx/intl.h> +#include "long_path_prefix.h" +#include "string_conv.h" +#include "system_func.h" +#include <wx/longlong.h> +#include "assert_static.h" +#include <bitset> +#include "global_func.h" +#include <limits> + + +bool dst::isFatDrive(const Zstring& fileName) //throw() +{ + using namespace ffs3; + + const size_t BUFFER_SIZE = MAX_PATH + 1; + wchar_t buffer[BUFFER_SIZE]; + +//this call is expensive: ~1.5 ms! +// if (!::GetVolumePathName(applyLongPathPrefix(fileName).c_str(), //__in LPCTSTR lpszFileName, +// buffer, //__out LPTSTR lpszVolumePathName, +// BUFFER_SIZE)) //__in DWORD cchBufferLength +// ... +// Zstring volumePath = buffer; +// if (!volumePath.EndsWith(common::FILE_NAME_SEPARATOR)) //a trailing backslash is required +// volumePath += common::FILE_NAME_SEPARATOR; + + //fast ::GetVolumePathName() clone: let's hope it's not too simple (doesn't honor mount points) + const Zstring nameFmt = removeLongPathPrefix(fileName); //throw() + const size_t pos = nameFmt.find(Zstr(":\\")); + if (pos != 1) //expect single letter volume + return false; + const Zstring volumePath(nameFmt.c_str(), 3); + + //suprisingly fast: ca. 0.03 ms per call! + if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName, + NULL, //__out LPTSTR lpVolumeNameBuffer, + 0, //__in DWORD nVolumeNameSize, + NULL, //__out_opt LPDWORD lpVolumeSerialNumber, + NULL, //__out_opt LPDWORD lpMaximumComponentLength, + NULL, //__out_opt LPDWORD lpFileSystemFlags, + buffer, //__out LPTSTR lpFileSystemNameBuffer, + BUFFER_SIZE)) //__in DWORD nFileSystemNameSize + { + assert(false); //shouldn't happen + return false; + } + const Zstring fileSystem = buffer; + + //DST hack seems to be working equally well for FAT and FAT32 (in particular creation time has 10^-2 s precision as advertised) + return fileSystem == Zstr("FAT") || + fileSystem == Zstr("FAT32"); +} + + +namespace +{ +FILETIME utcToLocal(const FILETIME& utcTime) //throw (std::runtime_error) +{ + //treat binary local time representation (which is invariant under DST time zone shift) as logical UTC: + FILETIME localTime = {}; + if (!::FileTimeToLocalFileTime( + &utcTime, //__in const FILETIME *lpFileTime, + &localTime)) //__out LPFILETIME lpLocalFileTime + { + const wxString errorMessage = wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME: ") + + wxT("(") + wxULongLong(utcTime.dwHighDateTime, utcTime.dwLowDateTime).ToString() + wxT(") ") + wxT("\n\n") + ffs3::getLastErrorFormatted(); + throw std::runtime_error(std::string((errorMessage).ToUTF8())); + } + return localTime; +} + + +FILETIME localToUtc(const FILETIME& localTime) //throw (std::runtime_error) +{ + //treat binary local time representation (which is invariant under DST time zone shift) as logical UTC: + FILETIME utcTime = {}; + if (!::LocalFileTimeToFileTime( + &localTime, //__in const FILETIME *lpLocalFileTime, + &utcTime)) //__out LPFILETIME lpFileTime + { + const wxString errorMessage = wxString(_("Conversion error:")) + wxT(" local FILETIME -> FILETIME: ") + + wxT("(") + wxULongLong(localTime.dwHighDateTime, localTime.dwLowDateTime).ToString() + wxT(") ") + wxT("\n\n") + ffs3::getLastErrorFormatted(); + throw std::runtime_error(std::string((errorMessage).ToUTF8())); + } + return utcTime; +} + + +int cmpFileTime(const FILETIME& a, const FILETIME& b) +{ + if (a.dwHighDateTime != b.dwHighDateTime) + return a.dwHighDateTime - b.dwHighDateTime; + return a.dwLowDateTime - b.dwLowDateTime; +} + + +template <class T> //convert wxULongLong and wxLongLong to FILETIME +inline +FILETIME toFiletime(const T& number) +{ + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); + assert(number.GetHi() >= 0); //for wxLongLong + + FILETIME output = {}; + output.dwHighDateTime = number.GetHi(); + output.dwLowDateTime = number.GetLo(); + return output; +} + + +inline +wxULongLong toULonglong(const FILETIME& fileTime) +{ + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); + + return wxULongLong(fileTime.dwHighDateTime, fileTime.dwLowDateTime); +} + + +inline +wxLongLong toLonglong(const FILETIME& fileTime) +{ + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); + assert(fileTime.dwHighDateTime <= static_cast<unsigned long>(std::numeric_limits<long>::max())); + + return wxLongLong(fileTime.dwHighDateTime, fileTime.dwLowDateTime); +} + + +//struct FILETIME {DWORD dwLowDateTime; DWORD dwHighDateTime;}; +const FILETIME FAT_MIN_TIME = {13374976, 27846544}; //1980 \ both are valid max/min FAT dates for 2 second precision +const FILETIME FAT_MAX_TIME = {14487552, 37251238}; //2107 / + +//http://en.wikipedia.org/wiki/File_Allocation_Table +const size_t PRECISION_WRITE_TIME = 20000000; //number of 100 ns per step -> 2 s +const size_t PRECISION_CREATE_TIME = 100000; // -> 1/100 s + +/* +Number of bits of information in create time: ln_2((FAT_MAX_TIME - FAT_MIN_TIME) / PRECISION_CREATE_TIME) = 38.55534023 +Number of bits of information in write time: 30.91148404 +*/ +//total size available to store data: +const size_t CREATE_TIME_INFO_BITS = 38; +// I. indicator that offset in II) is present +const size_t INDICATOR_EXISTING_BITS = 1; +// II. local<->UTC time offset +const size_t UTC_LOCAL_OFFSET_BITS = 7; +// III. indicator that offset in II) corresponds to current local write time (this could be a hash of the write time) +const size_t WRITE_TIME_HASH_BITS = CREATE_TIME_INFO_BITS - INDICATOR_EXISTING_BITS - UTC_LOCAL_OFFSET_BITS; + + +template <size_t precision> +FILETIME encodeRawInformation(wxULongLong rawInfo) +{ + rawInfo *= precision; + rawInfo += toULonglong(FAT_MIN_TIME); + + assert(rawInfo <= toULonglong(FAT_MAX_TIME)); + return toFiletime(rawInfo); +} + + +template <size_t precision> +wxULongLong extractRawInformation(const FILETIME& createTime) +{ + assert(cmpFileTime(FAT_MIN_TIME, createTime) <= 0); + assert(cmpFileTime(createTime, FAT_MAX_TIME) <= 0); + + //FAT create time ranges from 1980 - 2107 (2^7 years) with 1/100 seconds precision + wxULongLong rawInfo = toULonglong(createTime); + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); + + rawInfo -= toULonglong(FAT_MIN_TIME); + rawInfo /= precision; //reduce precision (FILETIME has unit 10^-7 s) + + assert(cmpFileTime(encodeRawInformation<precision>(rawInfo), createTime) == 0); //must be reversible + return rawInfo; +} + + +//convert write time to it's minimal representation (no restriction to FAT range "1980 - 2107") +wxULongLong extractRawWriteTime(const FILETIME& writeTime) +{ + wxULongLong rawInfo = toULonglong(writeTime); + assert(rawInfo % PRECISION_WRITE_TIME == 0); + rawInfo /= PRECISION_WRITE_TIME; //reduce precision (FILETIME has unit 10^-7 s) + return rawInfo; +} + + +//files with different resolution than 2 seconds are rounded up when written to FAT +FILETIME roundToFatWriteTime(const FILETIME& writeTime) +{ + wxULongLong rawData = toULonglong(writeTime); + + if (rawData % PRECISION_WRITE_TIME != 0) + rawData += PRECISION_WRITE_TIME; + + rawData /= PRECISION_WRITE_TIME; + rawData *= PRECISION_WRITE_TIME; + return toFiletime(rawData); +} + + +//get 7-bit value representing time shift in number of quarter-hours +std::bitset<UTC_LOCAL_OFFSET_BITS> getUtcLocalShift() +{ + FILETIME utcTime = FAT_MIN_TIME; + utcTime.dwHighDateTime += 5000000; //some arbitrary valid time + + const FILETIME localTime = utcToLocal(utcTime); + + const int timeShiftSec = ((toLonglong(localTime) - toLonglong(utcTime)) / 10000000).ToLong(); //time shift in seconds + + const int timeShiftQuarter = timeShiftSec / (60 * 15); //time shift in quarter-hours + + const int absValue = common::abs(timeShiftQuarter); //MSVC C++0x bug: std::bitset<>(unsigned long) is ambiguous + + if (std::bitset<UTC_LOCAL_OFFSET_BITS - 1>(absValue).to_ulong() != static_cast<unsigned long>(absValue) || //time shifts that big shouldn't be possible! + timeShiftSec % (60 * 15) != 0) //all known time shift have at least 15 minute granularity! + { + const wxString errorMessage = wxString(_("Conversion error:")) + wxT(" Unexpected UTC <-> local time shift: ") + + wxT("(") + wxLongLong(timeShiftSec).ToString() + wxT(") ") + wxT("\n\n") + ffs3::getLastErrorFormatted(); + throw std::runtime_error(std::string((errorMessage).ToUTF8())); + } + + std::bitset<UTC_LOCAL_OFFSET_BITS> output(absValue); + output[UTC_LOCAL_OFFSET_BITS - 1] = timeShiftQuarter < 0; //sign bit + return output; +} + + +//get time-zone shift in seconds +inline +int convertUtcLocalShift(std::bitset<UTC_LOCAL_OFFSET_BITS> rawShift) +{ + const bool hasSign = rawShift[UTC_LOCAL_OFFSET_BITS - 1]; + rawShift[UTC_LOCAL_OFFSET_BITS - 1] = false; + + assert_static(UTC_LOCAL_OFFSET_BITS <= sizeof(unsigned long) * 8); + return hasSign ? + rawShift.to_ulong() * 15 * 60 * -1 : + rawShift.to_ulong() * 15 * 60; +} +} + + +bool dst::fatHasUtcEncoded(const RawTime& rawTime) //"createTimeRaw" as retrieved by ::FindFirstFile() and ::GetFileAttributesEx(); throw (std::runtime_error) +{ + if ( cmpFileTime(rawTime.createTimeRaw, FAT_MIN_TIME) < 0 || + cmpFileTime(FAT_MAX_TIME, rawTime.createTimeRaw) < 0) + { + assert(false); //shouldn't be possible according to FAT specification + return false; + } + + const wxULongLong rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); + + assert_static(WRITE_TIME_HASH_BITS == 30); + return (extractRawWriteTime(utcToLocal(rawTime.writeTimeRaw)) & 0x3FFFFFFF) == (rawInfo & 0x3FFFFFFF) && //ensure write time wasn't changed externally + rawInfo >> (CREATE_TIME_INFO_BITS - INDICATOR_EXISTING_BITS) == 1; //extended data available +} + + +dst::RawTime dst::fatEncodeUtcTime(const FILETIME& writeTimeRealUtc) //throw (std::runtime_error) +{ + const FILETIME fatWriteTimeUtc = roundToFatWriteTime(writeTimeRealUtc); //writeTimeRealUtc may have incompatible precision (NTFS) + + //create time lets us store 40 bit of information + + //indicator that utc time is encoded -> hopefully results in a date long way in the future; but even if this bit is accidentally set, we still have the hash! + wxULongLong data = 1; + + const std::bitset<UTC_LOCAL_OFFSET_BITS> utcShift = getUtcLocalShift(); + data <<= UTC_LOCAL_OFFSET_BITS; + data |= utcShift.to_ulong(); + + data <<= WRITE_TIME_HASH_BITS; + data |= extractRawWriteTime(utcToLocal(fatWriteTimeUtc)) & 0x3FFFFFFF; //trim to last 30 bit of information + assert_static(WRITE_TIME_HASH_BITS == 30); + + const FILETIME encodedData = localToUtc(encodeRawInformation<PRECISION_CREATE_TIME>(data)); //localToUtc: make sure data is physically saved as FAT local time + assert(cmpFileTime(FAT_MIN_TIME, encodedData) <= 0); + assert(cmpFileTime(encodedData, FAT_MAX_TIME) <= 0); + + return RawTime(encodedData, fatWriteTimeUtc); //keep compatible with other applications, at least until DST shift actually occurs +} + + +FILETIME dst::fatDecodeUtcTime(const RawTime& rawTime) //return real UTC time; throw (std::runtime_error) +{ + if (!fatHasUtcEncoded(rawTime)) + return rawTime.writeTimeRaw; + + const wxULongLong rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); + + const std::bitset<UTC_LOCAL_OFFSET_BITS> rawShift(static_cast<int>(((rawInfo >> WRITE_TIME_HASH_BITS) & 0x7F).ToULong())); //static_cast<int>: a shame MSC... + assert_static(UTC_LOCAL_OFFSET_BITS == 7); + + const int timeShiftSec = convertUtcLocalShift(rawShift); + const FILETIME writeTimeLocal = utcToLocal(rawTime.writeTimeRaw); + + const wxLongLong realUTC = toLonglong(writeTimeLocal) - wxLongLong(timeShiftSec) * 10000000; + return toFiletime(realUTC); +} diff --git a/shared/dst_hack.h b/shared/dst_hack.h new file mode 100644 index 00000000..550098a2 --- /dev/null +++ b/shared/dst_hack.h @@ -0,0 +1,38 @@ +#ifndef DST_HACK_H_INCLUDED +#define DST_HACK_H_INCLUDED + +#include <wx/msw/wrapwin.h> //includes "windows.h" +#include "zstring.h" +#include <stdexcept> + + +namespace dst +{ +/* +Solve DST +-1h and time zone shift issues on FAT drives +------------------------------------------------------- +- (local) last write time is not touched! +- all additional metadata is encoded in local create time: + I. indicator that offset in II) is present + II. local<->UTC time offset + III. indicator that offset in II) corresponds to current local write time (a hash of local last write time) +*/ + +bool isFatDrive(const Zstring& fileName); //throw () + +//all subsequent functions may throw the std::runtime_error exception! + +struct RawTime //time as retrieved by ::FindFirstFile() and ::GetFileAttributesEx() +{ + RawTime(const FILETIME& create, const FILETIME& lastWrite) : createTimeRaw(create), writeTimeRaw(lastWrite) {} + FILETIME createTimeRaw; + FILETIME writeTimeRaw; +}; +//save UTC time resistant against DST/time zone shifts +bool fatHasUtcEncoded(const RawTime& rawTime); //as retrieved by ::FindFirstFile() and ::GetFileAttributesEx(); throw (std::runtime_error) + +RawTime fatEncodeUtcTime(const FILETIME& writeTimeRealUtc); //throw (std::runtime_error) +FILETIME fatDecodeUtcTime(const RawTime& rawTime); //return last write time in real UTC; throw (std::runtime_error) +} + +#endif // DST_HACK_H_INCLUDED diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp index 3f56abe4..5c6ce856 100644 --- a/shared/file_handling.cpp +++ b/shared/file_handling.cpp @@ -27,6 +27,7 @@ #include <wx/msw/wrapwin.h> //includes "windows.h" #include "long_path_prefix.h" #include <Aclapi.h> +#include "dst_hack.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -45,7 +46,7 @@ namespace #ifdef FFS_WIN Zstring resolveRelativePath(const Zstring& relativeName, DWORD proposedBufferSize = 1000) { - boost::scoped_array<DefaultChar> fullPath(new DefaultChar[proposedBufferSize]); + boost::scoped_array<Zchar> fullPath(new Zchar[proposedBufferSize]); const DWORD rv = ::GetFullPathName( relativeName.c_str(), //__in LPCTSTR lpFileName, proposedBufferSize, //__in DWORD nBufferLength, @@ -125,7 +126,6 @@ bool replaceMacro(wxString& macro) //macro without %-characters, return true if macro.EndsWith(wxT("\"")) && macro.length() >= 2) macro = wxString(macro.c_str() + 1, macro.length() - 2); - return true; } @@ -153,7 +153,7 @@ void expandMacros(wxString& text) } else { - rest = wxString() + SEPARATOR + rest; + rest = SEPARATOR + rest; expandMacros(rest); text = prefix + SEPARATOR + potentialMacro + rest; } @@ -166,17 +166,17 @@ void expandMacros(wxString& text) Zstring ffs3::getFormattedDirectoryName(const Zstring& dirname) { //Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. - //note: don't do directory formatting with wxFileName, as it doesn't respect //?/ - prefix! + //note: don't combine directory formatting with wxFileName, as it doesn't respect //?/ - prefix! wxString dirnameTmp = zToWx(dirname); - dirnameTmp.Trim(true); //remove whitespace characters from right - dirnameTmp.Trim(false); //remove whitespace characters from left + expandMacros(dirnameTmp); - if (dirnameTmp.empty()) //an empty string will later be returned as "\"; this is not desired - return Zstring(); + Zstring output = wxToZ(dirnameTmp); - //replace macros - expandMacros(dirnameTmp); + output.Trim(); + + if (output.empty()) //an empty string will later be returned as "\"; this is not desired + return Zstring(); /* resolve relative names; required by: @@ -188,12 +188,12 @@ Zstring ffs3::getFormattedDirectoryName(const Zstring& dirname) WINDOWS/LINUX: - detection of dependent directories, e.g. "\" and "C:\test" */ - dirnameTmp = zToWx(resolveRelativePath(wxToZ(dirnameTmp))); + output = resolveRelativePath(output); - if (!dirnameTmp.EndsWith(zToWx(common::FILE_NAME_SEPARATOR))) - dirnameTmp += zToWx(common::FILE_NAME_SEPARATOR); + if (!output.EndsWith(common::FILE_NAME_SEPARATOR)) + output += common::FILE_NAME_SEPARATOR; - return wxToZ(dirnameTmp); + return output; } @@ -546,17 +546,17 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns Zstring createTemp8Dot3Name(const Zstring& fileName) //find a unique 8.3 short name { - const Zstring pathPrefix = fileName.Find(common::FILE_NAME_SEPARATOR) != Zstring::npos ? + const Zstring pathPrefix = fileName.find(common::FILE_NAME_SEPARATOR) != Zstring::npos ? (fileName.BeforeLast(common::FILE_NAME_SEPARATOR) + common::FILE_NAME_SEPARATOR) : Zstring(); - Zstring extension = fileName.AfterLast(common::FILE_NAME_SEPARATOR).AfterLast(DefaultChar('.')); //extension needn't contain reasonable data + Zstring extension = fileName.AfterLast(common::FILE_NAME_SEPARATOR).AfterLast(Zchar('.')); //extension needn't contain reasonable data if (extension.empty()) - extension = DefaultStr("FFS"); + extension = Zstr("FFS"); extension.Truncate(3); for (int index = 0; index < 100000000; ++index) //filename must be representable by <= 8 characters { - const Zstring output = pathPrefix + numberToZstring(index) + DefaultChar('.') + extension; + const Zstring output = pathPrefix + Zstring::fromNumber(index) + Zchar('.') + extension; if (!ffs3::somethingExists(output)) //ensure uniqueness return output; } @@ -570,7 +570,7 @@ bool fix8Dot3NameClash(const Zstring& oldName, const Zstring& newName) //throw { using namespace ffs3; - if (newName.Find(common::FILE_NAME_SEPARATOR) == Zstring::npos) + if (newName.find(common::FILE_NAME_SEPARATOR) == Zstring::npos) return false; if (ffs3::somethingExists(newName)) //name OR directory! @@ -581,8 +581,8 @@ bool fix8Dot3NameClash(const Zstring& oldName, const Zstring& newName) //throw if ( !fileNameShort.empty() && !fileNameLong.empty() && - cmpFileName(fileNameOrig, fileNameShort) == 0 && - cmpFileName(fileNameShort, fileNameLong) != 0) + EqualFilename()(fileNameOrig, fileNameShort) && + !EqualFilename()(fileNameShort, fileNameLong)) { //we detected an event where newName is in shortname format (although it is intended to be a long name) and //writing target file failed because another unrelated file happens to have the same short name @@ -634,11 +634,11 @@ using ffs3::MoveFileCallback; class CopyCallbackImpl : public ffs3::CopyFileCallback //callback functionality { public: - CopyCallbackImpl(MoveFileCallback* callback) : moveCallback(callback) {} + CopyCallbackImpl(const Zstring& sourceFile, MoveFileCallback& callback) : sourceFile_(sourceFile), moveCallback(callback) {} virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred) { - switch (moveCallback->requestUiRefresh()) + switch (moveCallback.requestUiRefresh(sourceFile_)) { case MoveFileCallback::CONTINUE: return CopyFileCallback::CONTINUE; @@ -650,17 +650,27 @@ public: } private: - MoveFileCallback* moveCallback; + const Zstring sourceFile_; + MoveFileCallback& moveCallback; }; void ffs3::moveFile(const Zstring& sourceFile, const Zstring& targetFile, MoveFileCallback* callback) //throw (FileError); { + //call back once per file (moveFile() is called by moveDirectory()) + if (callback) + switch (callback->requestUiRefresh(sourceFile)) + { + case MoveFileCallback::CONTINUE: + break; + case MoveFileCallback::CANCEL: //a user aborted operation IS an error condition! + throw FileError(wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\"") + + wxT("\n\n") + _("Operation aborted!")); + } + if (somethingExists(targetFile)) //test file existence: e.g. Linux might silently overwrite existing symlinks - { - const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + _("Target file already existing!")); - } + throw FileError(wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\"") + + wxT("\n\n") + _("Target file already existing!")); //moving of symbolic links should work correctly: @@ -675,7 +685,7 @@ void ffs3::moveFile(const Zstring& sourceFile, const Zstring& targetFile, MoveFi //file is on a different volume: let's copy it - std::auto_ptr<CopyCallbackImpl> copyCallback(callback != NULL ? new CopyCallbackImpl(callback) : NULL); + std::auto_ptr<CopyCallbackImpl> copyCallback(callback != NULL ? new CopyCallbackImpl(sourceFile, *callback) : NULL); copyFile(sourceFile, targetFile, @@ -691,7 +701,8 @@ void ffs3::moveFile(const Zstring& sourceFile, const Zstring& targetFile, MoveFi removeFile(sourceFile); } - +namespace +{ class TraverseOneLevel : public ffs3::TraverseCallback { public: @@ -701,11 +712,11 @@ public: m_files(filesShort), m_dirs(dirsShort) {} - virtual void onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) { m_files.push_back(std::make_pair(Zstring(shortName), fullName)); } - virtual void onSymlink(const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details) + virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { if (details.dirLink) m_dirs.push_back(std::make_pair(Zstring(shortName), fullName)); @@ -713,7 +724,7 @@ public: m_files.push_back(std::make_pair(Zstring(shortName), fullName)); } - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) + virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName) { m_dirs.push_back(std::make_pair(Zstring(shortName), fullName)); return Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>(); //DON'T traverse into subdirs; moveDirectory works recursively! @@ -729,25 +740,63 @@ private: }; +struct RemoveCallbackImpl : public ffs3::RemoveDirCallback +{ + RemoveCallbackImpl(const Zstring& sourceDir, + const Zstring& targetDir, + MoveFileCallback& moveCallback) : + sourceDir_(sourceDir), + targetDir_(targetDir), + moveCallback_(moveCallback) {} + + virtual void requestUiRefresh(const Zstring& currentObject) + { + switch (moveCallback_.requestUiRefresh(sourceDir_)) + { + case MoveFileCallback::CONTINUE: + break; + case MoveFileCallback::CANCEL: //a user aborted operation IS an error condition! + throw ffs3::FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + ffs3::zToWx(sourceDir_) + wxT("\" ->\n\"") + + ffs3::zToWx(targetDir_) + wxT("\"") + wxT("\n\n") + _("Operation aborted!")); + } + } + +private: + const Zstring sourceDir_; + const Zstring targetDir_; + MoveFileCallback& moveCallback_; +}; +} + + void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExistingDirs, MoveFileCallback* callback) //throw (FileError); { using namespace ffs3; + //call back once per folder + if (callback) + switch (callback->requestUiRefresh(sourceDir)) + { + case MoveFileCallback::CONTINUE: + break; + case MoveFileCallback::CANCEL: //a user aborted operation IS an error condition! + throw FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + + zToWx(targetDir) + wxT("\"") + wxT("\n\n") + _("Operation aborted!")); + } + //handle symbolic links if (symlinkExists(sourceDir)) { createDirectory(targetDir, sourceDir, true, false); //copy symbolic link, don't copy permissions - removeDirectory(sourceDir); //if target is already another symlink or directory, sourceDir-symlink is silently deleted + removeDirectory(sourceDir, NULL); //if target is already another symlink or directory, sourceDir-symlink is silently deleted return; } if (somethingExists(targetDir)) { if (!ignoreExistingDirs) //directory or symlink exists (or even a file... this error will be caught later) - { - const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + zToWx(targetDir) + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + _("Target directory already existing!")); - } + throw FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + zToWx(targetDir) + wxT("\"") + + wxT("\n\n") + _("Target directory already existing!")); } else { @@ -764,25 +813,13 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool createDirectory(targetDir, sourceDir, false, false); //throw (FileError); don't copy permissions } - //call back once per folder - if (callback) - switch (callback->requestUiRefresh()) - { - case MoveFileCallback::CONTINUE: - break; - case MoveFileCallback::CANCEL: - //an user aborted operation IS an error condition! - throw FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + - zToWx(targetDir) + wxT("\"") + wxT("\n\n") + _("Operation aborted!")); - } - //move files/folders recursively TraverseOneLevel::NamePair fileList; //list of names: 1. short 2.long TraverseOneLevel::NamePair dirList; // //traverse source directory one level TraverseOneLevel traverseCallback(fileList, dirList); - traverseFolder(sourceDir, false, &traverseCallback); //traverse one level, don't follow symlinks + traverseFolder(sourceDir, false, traverseCallback); //traverse one level, don't follow symlinks const Zstring targetDirFormatted = targetDir.EndsWith(common::FILE_NAME_SEPARATOR) ? //ends with path separator targetDir : @@ -799,7 +836,8 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //attention: if move-operation was cancelled an exception is thrown => sourceDir is not deleted, as we wish! //delete source - removeDirectory(sourceDir); //throw (FileError); + std::auto_ptr<RemoveCallbackImpl> removeCallback(callback != NULL ? new RemoveCallbackImpl(sourceDir, targetDir, *callback) : NULL); + removeDirectory(sourceDir, removeCallback.get()); //throw (FileError); } @@ -831,18 +869,18 @@ public: m_files(files), m_dirs(dirs) {} - virtual void onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) + virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) { m_files.push_back(fullName); } - virtual void onSymlink(const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details) + virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { if (details.dirLink) m_dirs.push_back(fullName); else m_files.push_back(fullName); } - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) + virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName) { m_dirs.push_back(fullName); return Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>(); //DON'T traverse into subdirs; removeDirectory works recursively! @@ -858,7 +896,7 @@ private: }; -void ffs3::removeDirectory(const Zstring& directory) +void ffs3::removeDirectory(const Zstring& directory, RemoveDirCallback* callback) { //no error situation if directory is not existing! manual deletion relies on it! if (!somethingExists(directory)) @@ -898,13 +936,23 @@ void ffs3::removeDirectory(const Zstring& directory) //get all files and directories from current directory (WITHOUT subdirectories!) FilesDirsOnlyTraverser traverser(fileList, dirList); - ffs3::traverseFolder(directory, false, &traverser); //don't follow symlinks + ffs3::traverseFolder(directory, false, traverser); //don't follow symlinks + //delete files - std::for_each(fileList.begin(), fileList.end(), removeFile); + for (std::vector<Zstring>::const_iterator i = fileList.begin(); i != fileList.end(); ++i) + { + if (callback) callback->requestUiRefresh(*i); //call once per file + removeFile(*i); + } //delete directories recursively - std::for_each(dirList.begin(), dirList.end(), removeDirectory); //call recursively to correctly handle symbolic links + for (std::vector<Zstring>::const_iterator i = dirList.begin(); i != dirList.end(); ++i) + { + if (callback) callback->requestUiRefresh(*i); //and once per folder + removeDirectory(*i, callback); //call recursively to correctly handle symbolic links + } + //parent directory is deleted last #ifdef FFS_WIN @@ -919,16 +967,15 @@ void ffs3::removeDirectory(const Zstring& directory) } -//optionally: copy directory last change date, DO NOTHING if something fails void ffs3::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool deRefSymlinks) //throw (FileError) { #ifdef FFS_WIN - FILETIME creationTime = {0}; - FILETIME lastAccessTime = {0}; - FILETIME lastWriteTime = {0}; + FILETIME creationTime = {}; + FILETIME lastAccessTime = {}; + FILETIME lastWriteTime = {}; { - WIN32_FILE_ATTRIBUTE_DATA sourceAttr; + WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {}; if (!::GetFileAttributesEx(applyLongPathPrefix(sourceObj).c_str(), //__in LPCTSTR lpFileName, GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, &sourceAttr)) //__out LPVOID lpFileInformation @@ -969,8 +1016,31 @@ void ffs3::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, boo lastAccessTime = sourceAttr.ftLastAccessTime; lastWriteTime = sourceAttr.ftLastWriteTime; } + +//####################################### DST hack ########################################### + if ((sourceAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) //dst hack not (yet) required for directories (symlinks implicitly checked by isFatDrive()) + { + if (dst::isFatDrive(sourceObj)) //throw() + { + const dst::RawTime rawTime(creationTime, lastWriteTime); + if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) + { + lastWriteTime = dst::fatDecodeUtcTime(rawTime); //return last write time in real UTC, throw (std::runtime_error) + ::GetSystemTimeAsFileTime(&creationTime); //real creation time information is not available... + } + } + + if (dst::isFatDrive(targetObj)) //throw() + { + const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw (std::runtime_error) + creationTime = encodedTime.createTimeRaw; + lastWriteTime = encodedTime.writeTimeRaw; + } + } +//####################################### DST hack ########################################### } + HANDLE hTarget = ::CreateFile(applyLongPathPrefix(targetObj).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -984,18 +1054,31 @@ void ffs3::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, boo wxString errorMessage = wxString(_("Error changing modification time:")) + wxT("\n\"") + zToWx(targetObj) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); } - boost::shared_ptr<void> dummy(hTarget, ::CloseHandle); if (!::SetFileTime(hTarget, &creationTime, &lastAccessTime, - &lastWriteTime)) //return value not evalutated! + &lastWriteTime)) { wxString errorMessage = wxString(_("Error changing modification time:")) + wxT("\n\"") + zToWx(targetObj) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); } +#ifndef NDEBUG //dst hack: verify data written + if (dst::isFatDrive(targetObj)) //throw() + { + WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {}; + assert(::GetFileAttributesEx(applyLongPathPrefix(targetObj).c_str(), //__in LPCTSTR lpFileName, + GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, + &debugeAttr)); //__out LPVOID lpFileInformation + + assert(::CompareFileTime(&debugeAttr.ftCreationTime, &creationTime) == 0); + assert(::CompareFileTime(&debugeAttr.ftLastWriteTime, &lastWriteTime) == 0); + } +#endif + + #elif defined FFS_LINUX if (deRefSymlinks) { @@ -1071,7 +1154,7 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa DWORD cchFilePath, DWORD dwFlags); static const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = - util::loadDllFunction<GetFinalPathNameByHandleWFunc>(L"kernel32.dll", "GetFinalPathNameByHandleW"); + util::getDllFun<GetFinalPathNameByHandleWFunc>(L"kernel32.dll", "GetFinalPathNameByHandleW"); if (getFinalPathNameByHandle == NULL) throw FileError(wxString(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); @@ -1406,11 +1489,11 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat struct TryCleanUp { - static void tryDeleteDir(const Zstring& linkname) //throw () + static void tryDeleteDir(const Zstring& dirname) //throw () { try { - removeDirectory(linkname); + removeDirectory(dirname, NULL); } catch (...) {} } @@ -1483,6 +1566,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat guardNewDir.Dismiss(); //target has been created successfully! } + #elif defined FFS_LINUX //symbolic link handling if ( copyDirectorySymLinks && @@ -1537,13 +1621,9 @@ Zstring createTempName(const Zstring& filename) { Zstring output = filename + ffs3::TEMP_FILE_ENDING; -#ifndef _MSC_VER -#warning TEMP_FILE_ENDING -> harmonize with other "endings" remove trailing dot -#endif - //ensure uniqueness for (int i = 1; ffs3::somethingExists(output); ++i) - output = filename + DefaultChar('_') + numberToZstring(i) + ffs3::TEMP_FILE_ENDING; + output = filename + Zchar('_') + Zstring::fromNumber(i) + ffs3::TEMP_FILE_ENDING; return output; } @@ -1607,13 +1687,12 @@ DWORD CALLBACK copyCallbackInternal( bool supportForSymbolicLinks() { - OSVERSIONINFO osvi; - ::ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + OSVERSIONINFO osvi = {}; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //symbolic links are supported starting with Vista - if (GetVersionEx(&osvi)) - return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1, Vista majorVersion == 6 + if (::GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1; Vista majorVersion == 6, dwMinorVersion == 0 //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx return false; } @@ -1697,7 +1776,7 @@ void ffs3::copyFile(const Zstring& sourceFile, { //shadowFilename already contains prefix: E.g. "\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Program Files\FFS\sample.dat" - Zstring shadowFilename; + Zstring shadowFilename; try { shadowFilename = shadowCopyHandler->makeShadowCopy(sourceFile); //throw (FileError) diff --git a/shared/file_handling.h b/shared/file_handling.h index 36bf976f..af20ccf8 100644 --- a/shared/file_handling.h +++ b/shared/file_handling.h @@ -18,6 +18,11 @@ namespace ffs3 { +struct RemoveDirCallback; +struct MoveFileCallback; +struct CopyFileCallback; + + Zstring getFormattedDirectoryName(const Zstring& dirname); bool fileExists( const Zstring& filename); //throw() replaces wxFileExists()! @@ -47,21 +52,9 @@ wxULongLong getFilesize(const Zstring& filename); //throw (FileError) //file handling void removeFile(const Zstring& filename); //throw (FileError) -void removeDirectory(const Zstring& directory); //throw (FileError) +void removeDirectory(const Zstring& directory, RemoveDirCallback* callback = NULL); //throw (FileError) -struct MoveFileCallback //callback functionality -{ - virtual ~MoveFileCallback() {} - - enum Response - { - CONTINUE, - CANCEL - }; - virtual Response requestUiRefresh() = 0; //DON'T throw exceptions here, at least in Windows build! -}; - //rename file or directory: no copying!!! void renameFile(const Zstring& oldName, const Zstring& newName); //throw (FileError); @@ -76,17 +69,6 @@ void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool igno void createDirectory(const Zstring& directory, const Zstring& templateDir, bool copyDirectorySymLinks, bool copyFilePermissions); //throw (FileError); void createDirectory(const Zstring& directory); //throw (FileError); -> function overload avoids default parameter ambiguity issues! -struct CopyFileCallback //callback functionality -{ - virtual ~CopyFileCallback() {} - - enum Response - { - CONTINUE, - CANCEL - }; - virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred) = 0; //DON'T throw exceptions here, at least in Windows build! -}; void copyFile(const Zstring& sourceFile, //throw (FileError); const Zstring& targetFile, @@ -98,8 +80,45 @@ void copyFile(const Zstring& sourceFile, //throw (FileError); CopyFileCallback* callback); //may be NULL //Note: it MAY happen that copyFile() leaves temp files behind, e.g. temporary network drop. // => clean them up at an appropriate time (automatically set sync directions to delete them). They have the following ending: -const Zstring TEMP_FILE_ENDING = DefaultStr(".ffs_tmp"); -} +const Zstring TEMP_FILE_ENDING = Zstr(".ffs_tmp"); + + + + +//----------- callbacks --------------- +struct RemoveDirCallback +{ + virtual ~RemoveDirCallback() {} + virtual void requestUiRefresh(const Zstring& currentObject) = 0; +}; + + +struct MoveFileCallback //callback functionality +{ + virtual ~MoveFileCallback() {} + + enum Response + { + CONTINUE, + CANCEL + }; + virtual Response requestUiRefresh(const Zstring& currentObject) = 0; //DON'T throw exceptions here, at least in Windows build! +}; + + +struct CopyFileCallback //callback functionality +{ + virtual ~CopyFileCallback() {} + + enum Response + { + CONTINUE, + CANCEL + }; + virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred) = 0; //DON'T throw exceptions here, at least in Windows build! +}; +} + #endif //FILE_HANDLING_H_INCLUDED diff --git a/shared/file_id.cpp b/shared/file_id.cpp index f61108c0..0c8afa3d 100644 --- a/shared/file_id.cpp +++ b/shared/file_id.cpp @@ -13,7 +13,6 @@ #include <boost/shared_ptr.hpp> #elif defined FFS_LINUX - #endif diff --git a/shared/file_io.cpp b/shared/file_io.cpp index 345234fd..95c14c49 100644 --- a/shared/file_io.cpp +++ b/shared/file_io.cpp @@ -60,7 +60,8 @@ FileInput::FileInput(const Zstring& filename) : //throw FileError() { const DWORD lastError = ::GetLastError(); const wxString& errorMessage = wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(filename_) + wxT("\"") + wxT("\n\n") + ffs3::getLastErrorFormatted(lastError); - if (lastError == ERROR_FILE_NOT_FOUND) + if (lastError == ERROR_FILE_NOT_FOUND || + lastError == ERROR_PATH_NOT_FOUND) throw ErrorNotExisting(errorMessage); else throw FileError(errorMessage); diff --git a/shared/file_traverser.cpp b/shared/file_traverser.cpp index 8e9d5f0d..5d3f75f4 100644 --- a/shared/file_traverser.cpp +++ b/shared/file_traverser.cpp @@ -11,11 +11,14 @@ #include "string_conv.h" #include <boost/shared_ptr.hpp> #include <boost/scoped_array.hpp> +#include "assert_static.h" +#include <limits> #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" #include "WinIoCtl.h" #include "long_path_prefix.h" +#include "dst_hack.h" #elif defined FFS_LINUX #include <sys/stat.h> @@ -29,8 +32,8 @@ //{ //public: // DisableWow64Redirection() : -// wow64DisableWow64FsRedirection(util::loadDllFunction<Wow64DisableWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64DisableWow64FsRedirection")), -// wow64RevertWow64FsRedirection(util::loadDllFunction<Wow64RevertWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64RevertWow64FsRedirection")), +// wow64DisableWow64FsRedirection(util::getDllFun<Wow64DisableWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64DisableWow64FsRedirection")), +// wow64RevertWow64FsRedirection(util::getDllFun<Wow64RevertWow64FsRedirectionFunc>(L"kernel32.dll", "Wow64RevertWow64FsRedirection")), // oldValue(NULL) // { // if ( wow64DisableWow64FsRedirection && @@ -153,9 +156,13 @@ inline wxLongLong getWin32TimeInformation(const FILETIME& lastWriteTime) { //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) - wxLongLong writeTimeLong(wxInt32(lastWriteTime.dwHighDateTime), lastWriteTime.dwLowDateTime); + wxLongLong writeTimeLong(lastWriteTime.dwHighDateTime, lastWriteTime.dwLowDateTime); writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) writeTimeLong -= wxLongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s + + assert(lastWriteTime.dwHighDateTime <= static_cast<unsigned long>(std::numeric_limits<long>::max())); + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); return writeTimeLong; } @@ -198,224 +205,306 @@ bool setWin32FileInformationFromSymlink(const Zstring& linkName, ffs3::TraverseC #endif -template <bool followSymlinks> -void traverseDirectory(const Zstring& directory, ffs3::TraverseCallback* sink, int level) +class DirTraverser { - using namespace ffs3; - - if (level == 100) //catch endless recursion +public: + DirTraverser(const Zstring& baseDirectory, bool followSymlinks, ffs3::TraverseCallback& sink, ffs3::DstHackCallback* dstCallback) +#ifdef FFS_WIN + : isFatFileSystem(dst::isFatDrive(baseDirectory)) +#endif { - sink->onError(wxString(_("Endless loop when traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"")); - return; - } - + //format base directory name #ifdef FFS_WIN - //ensure directoryFormatted ends with backslash - const Zstring directoryFormatted = directory.EndsWith(common::FILE_NAME_SEPARATOR) ? - directory : - directory + common::FILE_NAME_SEPARATOR; + const Zstring& directoryFormatted = baseDirectory; - WIN32_FIND_DATA fileMetaData; - 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) - { - const DWORD lastError = ::GetLastError(); - if (lastError == ERROR_FILE_NOT_FOUND) - return; +#elif defined FFS_LINUX + const Zstring directoryFormatted = //remove trailing slash + baseDirectory.size() > 1 && baseDirectory.EndsWith(common::FILE_NAME_SEPARATOR) ? //exception: allow '/' + baseDirectory.BeforeLast(common::FILE_NAME_SEPARATOR) : + baseDirectory; +#endif - //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") + wxT("\n\n") + - ffs3::getLastErrorFormatted(lastError); + //traverse directories + if (followSymlinks) + traverse<true>(directoryFormatted, sink, 0); + else + traverse<false>(directoryFormatted, sink, 0); - sink->onError(errorMessage); - return; + //apply daylight saving time hack AFTER file traversing, to give separate feedback to user +#ifdef FFS_WIN + if (isFatFileSystem && dstCallback) + applyDstHack(*dstCallback); +#endif } - boost::shared_ptr<void> dummy(searchHandle, ::FindClose); - - do +private: + template <bool followSymlinks> + void traverse(const Zstring& directory, ffs3::TraverseCallback& sink, int level) { - //don't return "." and ".." - const wxChar* const shortName = fileMetaData.cFileName; - if ( shortName[0] == wxChar('.') && - ((shortName[1] == wxChar('.') && shortName[2] == wxChar('\0')) || - shortName[1] == wxChar('\0'))) - continue; + using namespace ffs3; - const Zstring fullName = directoryFormatted + shortName; - - const bool isSymbolicLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; - - if (isSymbolicLink && !followSymlinks) //evaluate symlink directly + if (level == 100) //catch endless recursion { - TraverseCallback::SymlinkInfo details; - details.lastWriteTimeRaw = getWin32TimeInformation(fileMetaData.ftLastWriteTime); - details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error - details.dirLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows - sink->onSymlink(shortName, fullName, details); + sink.onError(wxString(_("Endless loop when traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"")); + return; } - else if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) + +#ifdef FFS_WIN + //ensure directoryFormatted ends with backslash + const Zstring& directoryFormatted = directory.EndsWith(common::FILE_NAME_SEPARATOR) ? + directory : + directory + common::FILE_NAME_SEPARATOR; + + WIN32_FIND_DATA fileMetaData; + HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryFormatted + Zchar('*')).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) { - const TraverseCallback::ReturnValDir rv = sink->onDir(shortName, fullName); - switch (rv.returnCode) - { - case TraverseCallback::ReturnValDir::TRAVERSING_DIR_IGNORE: - break; + const DWORD lastError = ::GetLastError(); + if (lastError == ERROR_FILE_NOT_FOUND) + return; - case TraverseCallback::ReturnValDir::TRAVERSING_DIR_CONTINUE: - traverseDirectory<followSymlinks>(fullName, rv.subDirCb, level + 1); - break; - } + //else: we have a problem... report it: + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") + wxT("\n\n") + + ffs3::getLastErrorFormatted(lastError); + + sink.onError(errorMessage); + return; } - else //a file or symlink that is followed... + + boost::shared_ptr<void> dummy(searchHandle, ::FindClose); + + do { - TraverseCallback::FileInfo details; + //don't return "." and ".." + const Zchar* const shortName = fileMetaData.cFileName; + if ( shortName[0] == Zstr('.') && + ((shortName[1] == Zstr('.') && shortName[2] == Zstr('\0')) || + shortName[1] == Zstr('\0'))) + continue; + + const Zstring& fullName = directoryFormatted + shortName; - if (isSymbolicLink) //dereference symlinks! + const bool isSymbolicLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + + if (isSymbolicLink && !followSymlinks) //evaluate symlink directly + { + TraverseCallback::SymlinkInfo details; + details.lastWriteTimeRaw = getWin32TimeInformation(fileMetaData.ftLastWriteTime); + details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error + details.dirLink = (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows + sink.onSymlink(shortName, fullName, details); + } + else if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) { - if (!setWin32FileInformationFromSymlink(fullName, details)) + const TraverseCallback::ReturnValDir rv = sink.onDir(shortName, fullName); + switch (rv.returnCode) { - //broken symlink... - details.lastWriteTimeRaw = 0; //we are not interested in the modifiation time of the link - details.fileSize = 0; + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_IGNORE: + break; + + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_CONTINUE: + traverse<followSymlinks>(fullName, *rv.subDirCb, level + 1); + break; } } - else - setWin32FileInformation(fileMetaData.ftLastWriteTime, fileMetaData.nFileSizeHigh, fileMetaData.nFileSizeLow, details); + else //a file or symlink that is followed... + { + TraverseCallback::FileInfo details; - sink->onFile(shortName, fullName, details); - } - } - while (::FindNextFile(searchHandle, // handle to search - &fileMetaData)); // pointer to structure for data on found file + if (isSymbolicLink) //dereference symlinks! + { + if (!setWin32FileInformationFromSymlink(fullName, details)) + { + //broken symlink... + details.lastWriteTimeRaw = 0; //we are not interested in the modification time of the link + details.fileSize = 0; + } + } + else + { +//####################################### DST hack ########################################### + if (isFatFileSystem) + { + const dst::RawTime rawTime(fileMetaData.ftCreationTime, fileMetaData.ftLastWriteTime); + + if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) + fileMetaData.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) + else + markForDstHack.push_back(std::make_pair(fullName, fileMetaData.ftLastWriteTime)); + } +//####################################### DST hack ########################################### + setWin32FileInformation(fileMetaData.ftLastWriteTime, fileMetaData.nFileSizeHigh, fileMetaData.nFileSizeLow, details); + } - const DWORD lastError = ::GetLastError(); - if (lastError == ERROR_NO_MORE_FILES) - return; //everything okay + sink.onFile(shortName, fullName, details); + } + } + while (::FindNextFile(searchHandle, // handle to search + &fileMetaData)); // pointer to structure for data on found file - //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; - sink->onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted(lastError)); - return; + const DWORD lastError = ::GetLastError(); + if (lastError == ERROR_NO_MORE_FILES) + return; //everything okay -#elif defined FFS_LINUX - DIR* dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/" - if (dirObj == NULL) - { + //else: we have a problem... report it: const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; - sink->onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + sink.onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted(lastError)); return; - } - boost::shared_ptr<DIR> dummy(dirObj, &::closedir); //never close NULL handles! -> crash - - while (true) - { - errno = 0; //set errno to 0 as unfortunately this isn't done when readdir() returns NULL because it can't find any files - struct dirent* dirEntry = ::readdir(dirObj); - if (dirEntry == NULL) +#elif defined FFS_LINUX + DIR* dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/" + if (dirObj == NULL) { - if (errno == 0) - return; //everything okay - - //else: we have a problem... report it: const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; - sink->onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + sink.onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); return; } - //don't return "." and ".." - const DefaultChar* const shortName = dirEntry->d_name; - if ( shortName[0] == wxChar('.') && - ((shortName[1] == wxChar('.') && shortName[2] == wxChar('\0')) || - shortName[1] == wxChar('\0'))) - continue; + boost::shared_ptr<DIR> dummy(dirObj, &::closedir); //never close NULL handles! -> crash - const Zstring fullName = directory.EndsWith(common::FILE_NAME_SEPARATOR) ? //e.g. "/" - directory + shortName : - directory + common::FILE_NAME_SEPARATOR + shortName; - - struct stat fileInfo; - if (::lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks + while (true) { - const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(fullName) + wxT("\""); - sink->onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); - continue; - } + errno = 0; //set errno to 0 as unfortunately this isn't done when readdir() returns NULL because it can't find any files + struct dirent* dirEntry = ::readdir(dirObj); + if (dirEntry == NULL) + { + if (errno == 0) + return; //everything okay - const bool isSymbolicLink = S_ISLNK(fileInfo.st_mode); + //else: we have a problem... report it: + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; + sink.onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + return; + } - if (isSymbolicLink) - { - if (followSymlinks) //on Linux Symlinks need to be followed to evaluate whether they point to a file or directory + //don't return "." and ".." + const Zchar* const shortName = dirEntry->d_name; + if ( shortName[0] == Zstr('.') && + ((shortName[1] == Zstr('.') && shortName[2] == Zstr('\0')) || + shortName[1] == Zstr('\0'))) + continue; + + const Zstring& fullName = directory.EndsWith(common::FILE_NAME_SEPARATOR) ? //e.g. "/" + directory + shortName : + directory + common::FILE_NAME_SEPARATOR + shortName; + + struct stat fileInfo; + if (::lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks + { + const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(fullName) + wxT("\""); + sink.onError(errorMessage + wxT("\n\n") + ffs3::getLastErrorFormatted()); + continue; + } + + const bool isSymbolicLink = S_ISLNK(fileInfo.st_mode); + + if (isSymbolicLink) { - if (::stat(fullName.c_str(), &fileInfo) != 0) //stat() resolves symlinks + if (followSymlinks) //on Linux Symlinks need to be followed to evaluate whether they point to a file or directory { - //a broken symbolic link - TraverseCallback::FileInfo details; - details.lastWriteTimeRaw = 0; //we are not interested in the modifiation time of the link - details.fileSize = 0; - sink->onFile(shortName, fullName, details); //report broken symlink as file! + if (::stat(fullName.c_str(), &fileInfo) != 0) //stat() resolves symlinks + { + //a broken symbolic link + TraverseCallback::FileInfo details; + details.lastWriteTimeRaw = 0; //we are not interested in the modifiation time of the link + details.fileSize = 0; + sink.onFile(shortName, fullName, details); //report broken symlink as file! + continue; + } + } + else //evaluate symlink directly + { + TraverseCallback::SymlinkInfo details; + details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second + details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error + details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); //S_ISDIR and S_ISLNK are mutually exclusive on Linux => need to follow link + sink.onSymlink(shortName, fullName, details); continue; } } - else //evaluate symlink directly + + //fileInfo contains dereferenced data in any case from here on + + if (S_ISDIR(fileInfo.st_mode)) //a directory... cannot be a symlink on Linux in this case { - TraverseCallback::SymlinkInfo details; + const TraverseCallback::ReturnValDir rv = sink.onDir(shortName, fullName); + switch (rv.returnCode) + { + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_IGNORE: + break; + + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_CONTINUE: + traverse<followSymlinks>(fullName, *rv.subDirCb, level + 1); + break; + } + } + else //a file... (or symlink; pathological!) + { + TraverseCallback::FileInfo details; details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second - details.targetPath = getSymlinkTarget(fullName); //throw(); returns empty string on error - details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); //S_ISDIR and S_ISLNK are mutually exclusive on Linux => need to follow link - sink->onSymlink(shortName, fullName, details); - continue; + details.fileSize = fileInfo.st_size; + + sink.onFile(shortName, fullName, details); } } +#endif + } - //fileInfo contains dereferenced data in any case from here on - if (S_ISDIR(fileInfo.st_mode)) //a directory... cannot be a symlink on Linux in this case +#ifdef FFS_WIN +//####################################### DST hack ########################################### + void applyDstHack(ffs3::DstHackCallback& dstCallback) + { + for (FilenameTimeList::const_iterator i = markForDstHack.begin(); i != markForDstHack.end(); ++i) { - const TraverseCallback::ReturnValDir rv = sink->onDir(shortName, fullName); - switch (rv.returnCode) + dstCallback.requestUiRefresh(i->first); + + HANDLE hTarget = ::CreateFile(ffs3::applyLongPathPrefix(i->first).c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hTarget == INVALID_HANDLE_VALUE) + assert(false); //don't throw exceptions due to dst hack here + else { - case TraverseCallback::ReturnValDir::TRAVERSING_DIR_IGNORE: - break; + boost::shared_ptr<void> dummy2(hTarget, ::CloseHandle); - case TraverseCallback::ReturnValDir::TRAVERSING_DIR_CONTINUE: - traverseDirectory<followSymlinks>(fullName, rv.subDirCb, level + 1); - break; - } - } - else //a file... (or symlink; pathological!) - { - TraverseCallback::FileInfo details; - details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second - details.fileSize = fileInfo.st_size; + const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw (std::runtime_error) + + if (!::SetFileTime(hTarget, + &encodedTime.createTimeRaw, + NULL, + &encodedTime.writeTimeRaw)) + assert(false); //don't throw exceptions due to dst hack here + +#ifndef NDEBUG //dst hack: verify data written; attention: this check may fail for "sync.ffs_lock" + WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {}; + assert(::GetFileAttributesEx(ffs3::applyLongPathPrefix(i->first).c_str(), //__in LPCTSTR lpFileName, + GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, + &debugeAttr)); //__out LPVOID lpFileInformation - sink->onFile(shortName, fullName, details); + assert(::CompareFileTime(&debugeAttr.ftCreationTime, &encodedTime.createTimeRaw) == 0); + assert(::CompareFileTime(&debugeAttr.ftLastWriteTime, &encodedTime.writeTimeRaw) == 0); +#endif + } } } + + const bool isFatFileSystem; + typedef std::vector<std::pair<Zstring, FILETIME> > FilenameTimeList; + FilenameTimeList markForDstHack; +//####################################### DST hack ########################################### #endif -} +}; -void ffs3::traverseFolder(const Zstring& directory, - bool followSymlinks, - TraverseCallback* sink) +void ffs3::traverseFolder(const Zstring& directory, bool followSymlinks, TraverseCallback& sink, DstHackCallback* dstCallback) { -#ifdef FFS_WIN - const Zstring& directoryFormatted = directory; -#elif defined FFS_LINUX - const Zstring directoryFormatted = //remove trailing slash - directory.size() > 1 && directory.EndsWith(common::FILE_NAME_SEPARATOR) ? //exception: allow '/' - directory.BeforeLast(common::FILE_NAME_SEPARATOR) : - directory; -#endif - - if (followSymlinks) - traverseDirectory<true>(directoryFormatted, sink, 0); - else - traverseDirectory<false>(directoryFormatted, sink, 0); + DirTraverser(directory, followSymlinks, sink, dstCallback); } diff --git a/shared/file_traverser.h b/shared/file_traverser.h index d61ff1cd..61237834 100644 --- a/shared/file_traverser.h +++ b/shared/file_traverser.h @@ -33,9 +33,8 @@ public: bool dirLink; //"true": point to dir; "false": point to file (or broken Link on Linux) }; - class ReturnValDir + struct ReturnValDir { - public: enum ReturnValueEnh { TRAVERSING_DIR_IGNORE, @@ -43,7 +42,7 @@ public: }; ReturnValDir(Loki::Int2Type<TRAVERSING_DIR_IGNORE>) : returnCode(TRAVERSING_DIR_IGNORE), subDirCb(NULL) {} - ReturnValDir(Loki::Int2Type<TRAVERSING_DIR_CONTINUE>, TraverseCallback* subDirCallback) : returnCode(TRAVERSING_DIR_CONTINUE), subDirCb(subDirCallback) {} + ReturnValDir(Loki::Int2Type<TRAVERSING_DIR_CONTINUE>, TraverseCallback& subDirCallback) : returnCode(TRAVERSING_DIR_CONTINUE), subDirCb(&subDirCallback) {} const ReturnValueEnh returnCode; TraverseCallback* const subDirCb; @@ -51,14 +50,28 @@ public: //overwrite these virtual methods virtual void onError(const wxString& errorText) = 0; - virtual void onFile( const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) = 0; - virtual void onSymlink( const DefaultChar* shortName, const Zstring& fullName, const SymlinkInfo& details) = 0; - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) = 0; + virtual void onFile( const Zchar* shortName, const Zstring& fullName, const FileInfo& details) = 0; + virtual void onSymlink( const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) = 0; + virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName) = 0; }; + +#ifdef FFS_WIN +struct DstHackCallback +{ + virtual ~DstHackCallback() {} + virtual void requestUiRefresh(const Zstring& filename) = 0; //applying DST hack imposes significant one-time performance drawback => callback to inform user +}; +#else +struct DstHackCallback; //DST hack not required on Linux +#endif + //custom traverser with detail information about files //directory may end with PATH_SEPARATOR -void traverseFolder(const Zstring& directory, bool followSymlinks, TraverseCallback* sink); //throw(); +void traverseFolder(const Zstring& directory, //throw(); + bool followSymlinks, + TraverseCallback& sink, + DstHackCallback* dstCallback = NULL); //apply DST hack if callback is supplied //followSymlinks: //"true": Symlinks dereferenced and reported via onFile() and onDir() => onSymlink not used! //"false": Symlinks directly reported via onSymlink(), directory symlinks are not followed diff --git a/shared/global_func.cpp b/shared/global_func.cpp index d1ab9d2c..c3d76c57 100644 --- a/shared/global_func.cpp +++ b/shared/global_func.cpp @@ -16,33 +16,6 @@ size_t common::getDigitCount(size_t number) //count number of digits return number == 0 ? 1 : static_cast<size_t>(::log10(static_cast<double>(number))) + 1; } - -//############################################################################ -Performance::Performance() : - resultWasShown(false), - timer(new wxStopWatch) -{ - timer->Start(); -} - - -Performance::~Performance() -{ - //keep non-inline destructor for std::auto_ptr to work with forward declaration - - if (!resultWasShown) - showResult(); -} - - -void Performance::showResult() -{ - resultWasShown = true; - wxMessageBox(wxLongLong(timer->Time()).ToString() + wxT(" ms")); - timer->Start(); //reset timer -} - - //############################################################################ DebugLog::DebugLog() : lineCount(0), diff --git a/shared/global_func.h b/shared/global_func.h index ba455371..c3994ca0 100644 --- a/shared/global_func.h +++ b/shared/global_func.h @@ -74,24 +74,6 @@ ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last //############################################################################ -class Performance -{ -public: - wxDEPRECATED(Performance()); //generate compiler warnings as a reminder to remove code after measurements - ~Performance(); - void showResult(); - -private: - bool resultWasShown; - std::auto_ptr<wxStopWatch> timer; -}; - -//two macros for quick performance measurements -#define PERF_START Performance a; -#define PERF_STOP a.showResult(); - - -//############################################################################ class wxFile; class DebugLog { diff --git a/shared/guid.cpp b/shared/guid.cpp index d359c29c..b20a1143 100644 --- a/shared/guid.cpp +++ b/shared/guid.cpp @@ -6,7 +6,17 @@ // #include "guid.h" #include <boost/uuid/uuid.hpp> + +//boost really should clean a bit up... +#ifdef __MINGW32__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif #include <boost/uuid/uuid_generators.hpp> +#ifdef __MINGW32__ +#pragma GCC diagnostic pop +#endif + #include <cassert> #include <algorithm> #include <vector> diff --git a/shared/lock.cpp b/shared/lock.cpp deleted file mode 100644 index 6b3dbcbb..00000000 --- a/shared/lock.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#include "lock.h" -#include "file_handling.h" -// -// -//util::LockDirectory::LockDirectory(const Zstring& dirname) -//{ -// -//} -// -// -//util::LockDirectory::~LockDirectory() -//{ -//} -// -// -//bool util::LockDirectoryisLocked(const Zstring& dirname); diff --git a/shared/lock.h b/shared/lock.h deleted file mode 100644 index f416f994..00000000 --- a/shared/lock.h +++ /dev/null @@ -1,26 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** -// -#ifndef LOCK_H_INCLUDED -#define LOCK_H_INCLUDED - -#include "zstring.h" -#include <vector> - -//namespace Utility -//{ -//class LockDirectory -//{ -//public: -// LockDirectory(const Zstring& dirname); -// ~LockDirectory(); -// -//private: -// std::vector<Zstring> toBeReleased; //list of files that will be deleted -//}; -//} - -#endif //LOCK_H_INCLUDED diff --git a/shared/loki/SmallObj.cpp b/shared/loki/SmallObj.cpp index a2911bb1..adb54c55 100644 --- a/shared/loki/SmallObj.cpp +++ b/shared/loki/SmallObj.cpp @@ -2,21 +2,21 @@ // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: -// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. -// Permission to use, copy, modify, distribute and sell this software for any -// purpose is hereby granted without fee, provided that the above copyright -// notice appear in all copies and that both that copyright notice and this +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. -// The author or Addison-Wesley Longman make no representations about the -// suitability of this software for any purpose. It is provided "as is" +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // $Id: SmallObj.cpp 823 2007-05-08 10:48:40Z lfittl $ -#include <loki/SmallObj.h> +#include "SmallObj.h" #include <cassert> #include <climits> @@ -359,7 +359,7 @@ void* Chunk::Allocate(std::size_t blockSize) { if ( IsFilled() ) return NULL; - assert((firstAvailableBlock_ * blockSize) / blockSize == + assert((firstAvailableBlock_ * blockSize) / blockSize == firstAvailableBlock_); unsigned char * pResult = pData_ + (firstAvailableBlock_ * blockSize); firstAvailableBlock_ = *pResult; @@ -503,7 +503,7 @@ bool Chunk::IsBlockAvailable( void * p, unsigned char numBlocks, std::size_t blockSize ) const { (void) numBlocks; - + if ( IsFilled() ) return false; @@ -860,8 +860,8 @@ void * FixedAllocator::Allocate( void ) } } else if ( allocChunk_ == emptyChunk_) - // detach emptyChunk_ from allocChunk_, because after - // calling allocChunk_->Allocate(blockSize_); the chunk + // detach emptyChunk_ from allocChunk_, because after + // calling allocChunk_->Allocate(blockSize_); the chunk // is no longer empty. emptyChunk_ = NULL; @@ -997,7 +997,7 @@ void FixedAllocator::DoDeallocate(void* p) assert( lastChunk->HasAvailable( numBlocks_ ) ); lastChunk->Release(); chunks_.pop_back(); - if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() ) + if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() ) allocChunk_ = deallocChunk_; } emptyChunk_ = deallocChunk_; @@ -1040,7 +1040,7 @@ void * DefaultAllocator( std::size_t numBytes, bool doThrow ) // DefaultDeallocator --------------------------------------------------------- /** @ingroup SmallObjectGroupInternal - Calls default deallocator when SmallObjAllocator decides not to handle a + Calls default deallocator when SmallObjAllocator decides not to handle a request. The default deallocator could be the global delete operator or the free function. The free function is the preferred default deallocator since it matches malloc which is the preferred default allocator. SmallObjAllocator diff --git a/shared/long_path_prefix.cpp b/shared/long_path_prefix.cpp index bc784f70..1c17065c 100644 --- a/shared/long_path_prefix.cpp +++ b/shared/long_path_prefix.cpp @@ -9,8 +9,8 @@ //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"); +const Zstring LONG_PATH_PREFIX = Zstr("\\\\?\\"); +const Zstring LONG_PATH_PREFIX_UNC = Zstr("\\\\?\\UNC"); template <size_t max_path> inline @@ -19,8 +19,8 @@ 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 + if (path.StartsWith(Zstr("\\\\"))) //UNC-name, e.g. \\zenju-pc\Users + return LONG_PATH_PREFIX_UNC + path.AfterFirst(Zchar('\\')); //convert to \\?\UNC\zenju-pc\Users else return LONG_PATH_PREFIX + path; //prepend \\?\ prefix } @@ -49,9 +49,9 @@ Zstring ffs3::removeLongPathPrefix(const Zstring& path) //throw() { Zstring finalPath = path; if (path.StartsWith(LONG_PATH_PREFIX_UNC)) //UNC-name - finalPath.Replace(LONG_PATH_PREFIX_UNC, DefaultStr("\\"), false); + finalPath.Replace(LONG_PATH_PREFIX_UNC, Zstr("\\"), false); else - finalPath.Replace(LONG_PATH_PREFIX, DefaultStr(""), false); + finalPath.Replace(LONG_PATH_PREFIX, Zstr(""), false); return finalPath; } diff --git a/shared/perf.h b/shared/perf.h index 62473259..e4e279bb 100644 --- a/shared/perf.h +++ b/shared/perf.h @@ -4,13 +4,23 @@ // * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // -#include <windows.h> +#ifndef DEBUG_PERF_HEADER +#define DEBUG_PERF_HEADER + +//#define WIN32_LEAN_AND_MEAN -> not in a header +#include <wx/msw/wrapwin.h> //includes "windows.h" #include <sstream> +#ifdef __MINGW32__ + #define DEPRECATED(x) x __attribute__ ((deprecated)) +#elif defined _MSC_VER + #define DEPRECATED(x) __declspec(deprecated) x +#endif + class Performance { public: - Performance() : resultWasShown(false), startTime(::GetTickCount()) {} + DEPRECATED(Performance()) : resultWasShown(false), startTime(::GetTickCount()) {} ~Performance() { @@ -20,18 +30,16 @@ public: void showResult() { - resultWasShown = true; - - const DWORD currentTime = ::GetTickCount(); - const DWORD delta = currentTime - startTime; - startTime = currentTime; - + const DWORD delta = ::GetTickCount() - startTime; std::ostringstream ss; ss << delta << " ms"; - + ::MessageBoxA(NULL, ss.str().c_str(), "Timer", 0); - } + resultWasShown = true; + startTime = ::GetTickCount(); //don't include call to MessageBox()! + } + private: bool resultWasShown; DWORD startTime; @@ -40,3 +48,5 @@ private: //two macros for quick performance measurements #define PERF_START Performance a; #define PERF_STOP a.showResult(); + +#endif //DEBUG_PERF_HEADER
\ No newline at end of file diff --git a/shared/recycler.cpp b/shared/recycler.cpp index 1a73e105..31257a65 100644 --- a/shared/recycler.cpp +++ b/shared/recycler.cpp @@ -82,17 +82,17 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( if (useIFileOperation) //new recycle bin usage: available since Vista { - std::vector<const wchar_t*> fileNames; + std::vector<const wchar_t*> fileNames; std::transform(filesToDelete.begin(), filesToDelete.end(), std::back_inserter(fileNames), std::mem_fun_ref(&Zstring::c_str)); - using namespace FileOp; + using namespace fileop; static const MoveToRecycleBinFct moveToRecycler = - util::loadDllFunction<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName); + util::getDllFun<MoveToRecycleBinFct>(getRecyclerDllName().c_str(), moveToRecycleBinFctName); static const GetLastErrorFct getLastError = - util::loadDllFunction<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName); + util::getDllFun<GetLastErrorFct>(getRecyclerDllName().c_str(), getLastErrorFctName); if (moveToRecycler == NULL || getLastError == NULL) throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + fileNames[0] + wxT("\"\n\n") + //report first file only... better than nothing @@ -103,11 +103,11 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( // std::transform(filesToDelete.begin(), filesToDelete.end(), // std::back_inserter(temp), std::ptr_fun(ffs3::removeLongPathPrefix)); //::IFileOperation() can't handle \\?\-prefix! - if (!(*moveToRecycler)(&fileNames[0], //array must not be empty - fileNames.size())) + if (!moveToRecycler(&fileNames[0], //array must not be empty + fileNames.size())) { wchar_t errorMessage[2000]; - (*getLastError)(errorMessage, 2000); + getLastError(errorMessage, 2000); throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + fileNames[0] + wxT("\"\n\n") + //report first file only... better than nothing wxT("(") + errorMessage + wxT(")")); } @@ -121,7 +121,7 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw ( //filenameDoubleNull += removeLongPathPrefix(*i); //::SHFileOperation() can't handle \\?\-prefix! //You should use fully-qualified path names with this function. Using it with relative path names is not thread safe. filenameDoubleNull += *i; //::SHFileOperation() can't handle \\?\-prefix! - filenameDoubleNull += DefaultChar(0); + filenameDoubleNull += Zchar(0); } SHFILEOPSTRUCT fileOp; @@ -166,8 +166,8 @@ void ffs3::moveToRecycleBin(const Zstring& fileToDelete) //throw (FileError) try { if (!fileObj->trash()) - throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(fileToDelete) + wxT("\"\n\n") + - wxT("(") + wxT("unknown error") + wxT(")")); + throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(fileToDelete) + wxT("\"\n\n") + + wxT("(") + wxT("unknown error") + wxT(")")); } catch (const Glib::Error& errorObj) { diff --git a/shared/serialize.h b/shared/serialize.h index 99dd83d5..7c4fcd5e 100644 --- a/shared/serialize.h +++ b/shared/serialize.h @@ -131,14 +131,14 @@ Zstring readString(wxInputStream& stream) //read string from file stream const size_t strLength = readNumber<size_t>(stream); if (strLength <= 1000) { - DefaultChar buffer[1000]; - stream.Read(buffer, sizeof(DefaultChar) * strLength); + Zchar buffer[1000]; + stream.Read(buffer, sizeof(Zchar) * strLength); return Zstring(buffer, strLength); } else { - boost::scoped_array<DefaultChar> buffer(new DefaultChar[strLength]); - stream.Read(buffer.get(), sizeof(DefaultChar) * strLength); + boost::scoped_array<Zchar> buffer(new Zchar[strLength]); + stream.Read(buffer.get(), sizeof(Zchar) * strLength); return Zstring(buffer.get(), strLength); } } @@ -148,7 +148,7 @@ inline void writeString(wxOutputStream& stream, const Zstring& str) //write string to filestream { writeNumber<size_t>(stream, str.length()); - stream.Write(str.c_str(), sizeof(DefaultChar) * str.length()); + stream.Write(str.c_str(), sizeof(Zchar) * str.length()); } diff --git a/shared/shadow.cpp b/shared/shadow.cpp index b38103de..39f21d2a 100644 --- a/shared/shadow.cpp +++ b/shared/shadow.cpp @@ -14,6 +14,7 @@ #include "build_info.h" #include "ShadowCopy\shadow.h" #include "string_conv.h" +#include "Loki/ScopeGuard.h" using shadow::ShadowCopy; using shadow::WaitingForShadow; @@ -41,17 +42,17 @@ bool newerThanXP() bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx) { //dynamically load windows API function - typedef BOOL (WINAPI *IsWow64ProcessFunc)( + typedef BOOL (WINAPI *IsWow64ProcessFun)( HANDLE hProcess, PBOOL Wow64Process); - static const IsWow64ProcessFunc isWow64Process = - util::loadDllFunction<IsWow64ProcessFunc>(L"kernel32.dll", "IsWow64Process"); + static const IsWow64ProcessFun isWow64Process = + util::getDllFun<IsWow64ProcessFun>(L"kernel32.dll", "IsWow64Process"); if (isWow64Process) { BOOL isWow64 = FALSE; - if ((*isWow64Process)(::GetCurrentProcess(), &isWow64)) + if (isWow64Process(::GetCurrentProcess(), &isWow64)) return isWow64 == TRUE; } @@ -86,7 +87,6 @@ const std::wstring& getShadowDllName() //############################################################################################################# ShadowCopy::ShadowCopy(WaitingForShadow* callback) : callback_(callback) {} -ShadowCopy::~ShadowCopy() {} //std::auto_ptr: keep non-inline //############################################################################################################# @@ -94,16 +94,15 @@ class ShadowCopy::ShadowVolume { public: ShadowVolume(const Zstring& volumeNameFormatted) : //throw(FileError) - realVol(volumeNameFormatted), - backupHandle(NULL) + backupHandle(0) { using namespace shadow; if (!createShadowCopy) - createShadowCopy = util::loadDllFunction<CreateShadowCopyFct>(getShadowDllName(), createShadowCopyFctName); + createShadowCopy = util::getDllFun<CreateShadowCopyFct>(getShadowDllName(), createShadowCopyFctName); if (!releaseShadowCopy) - releaseShadowCopy = util::loadDllFunction<ReleaseShadowCopyFct>(getShadowDllName(), releaseShadowCopyFctName); + releaseShadowCopy = util::getDllFun<ReleaseShadowCopyFct>(getShadowDllName(), releaseShadowCopyFctName); //check if shadow copy dll was loaded correctly if ( createShadowCopy == NULL || @@ -138,7 +137,7 @@ public: ~ShadowVolume() { - releaseShadowCopy(backupHandle); + releaseShadowCopy(backupHandle); //fast! no performance optimization necessary } Zstring getShadowVolume() const //trailing path separator @@ -146,11 +145,6 @@ public: return shadowVol; } - Zstring getRealVolume() const //trailing path separator - { - return realVol; - } - private: ShadowVolume(const ShadowVolume&); ShadowVolume& operator=(const ShadowVolume&); @@ -159,9 +153,8 @@ private: static shadow::ReleaseShadowCopyFct releaseShadowCopy; Zstring shadowVol; - const Zstring realVol; - void* backupHandle; + ShadowHandle backupHandle; }; @@ -195,9 +188,14 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile) throw FileError(msg); } - if (!shadowVol.get() || shadowVol->getRealVolume() != volumeNameFormatted) - shadowVol.reset(new ShadowVolume(volumeNameFormatted)); //throw (FileError) + //get or create instance of shadow volume + VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted); + if (iter == shadowVol.end()) + { + boost::shared_ptr<ShadowVolume> newEntry(new ShadowVolume(volumeNameFormatted)); + iter = shadowVol.insert(std::make_pair(volumeNameFormatted, newEntry)).first; + } //return filename alias on shadow copy volume - return shadowVol->getShadowVolume() + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); + return iter->second->getShadowVolume() + Zstring(inputFile.c_str() + pos + volumeNameFormatted.length()); } diff --git a/shared/shadow.h b/shared/shadow.h index 60d30bbd..2be44b41 100644 --- a/shared/shadow.h +++ b/shared/shadow.h @@ -13,7 +13,8 @@ use in windows build only! #include "zstring.h" #include "file_error.h" -#include <memory> +#include <map> +#include <boost/shared_ptr.hpp> namespace shadow @@ -22,7 +23,7 @@ struct WaitingForShadow { virtual ~WaitingForShadow() {} virtual void requestUiRefresh() = 0; //allowed to throw exceptions - virtual void updateStatusText(const Zstring& text) = 0; + virtual void reportInfo(const Zstring& text) = 0; }; @@ -30,7 +31,6 @@ class ShadowCopy //buffer access to Windows Volume Shadow Copy Service { public: ShadowCopy(WaitingForShadow* callback); - ~ShadowCopy(); Zstring makeShadowCopy(const Zstring& inputFile); //throw(FileError); returns filename on shadow copy @@ -41,7 +41,8 @@ private: WaitingForShadow* callback_; class ShadowVolume; - std::auto_ptr<ShadowVolume> shadowVol; + typedef std::map<Zstring, boost::shared_ptr<ShadowVolume>, LessFilename> VolNameShadowMap; + VolNameShadowMap shadowVol; }; } diff --git a/shared/string_conv.h b/shared/string_conv.h index bbaef713..bb8f6c7e 100644 --- a/shared/string_conv.h +++ b/shared/string_conv.h @@ -14,8 +14,8 @@ namespace ffs3 { //conversion from Zstring to wxString wxString zToWx(const Zstring& str); -wxString zToWx(const DefaultChar* str); -wxString zToWx(DefaultChar ch); +wxString zToWx(const Zchar* str); +wxString zToWx(Zchar ch); //conversion from wxString to Zstring Zstring wxToZ(const wxString& str); Zstring wxToZ(const wxChar* str); @@ -52,39 +52,39 @@ Zstring wxToZ(wxChar ch); inline wxString zToWx(const Zstring& str) { -#ifdef ZSTRING_CHAR - return wxString::FromUTF8(str.c_str(), str.length()); -#elif defined ZSTRING_WIDE_CHAR +#ifdef FFS_WIN return wxString(str.c_str(), str.length()); +#elif defined FFS_LINUX + return wxString::FromUTF8(str.c_str(), str.length()); #endif } inline -wxString zToWx(const DefaultChar* str) +wxString zToWx(const Zchar* str) { -#ifdef ZSTRING_CHAR - return wxString::FromUTF8(str); -#elif defined ZSTRING_WIDE_CHAR +#ifdef FFS_WIN return str; +#elif defined FFS_LINUX + return wxString::FromUTF8(str); #endif } inline -wxString zToWx(DefaultChar ch) +wxString zToWx(Zchar ch) { - return zToWx(Zstring() + ch); + return zToWx(Zstring(ch)); } //----------------------------------------------------------------- inline Zstring wxToZ(const wxString& str) { -#ifdef ZSTRING_CHAR - return Zstring(str.ToUTF8()); -#elif defined ZSTRING_WIDE_CHAR +#ifdef FFS_WIN return Zstring(str.c_str(), str.length()); +#elif defined FFS_LINUX + return Zstring(str.ToUTF8()); #endif } @@ -92,10 +92,10 @@ Zstring wxToZ(const wxString& str) inline Zstring wxToZ(const wxChar* str) { -#ifdef ZSTRING_CHAR - return Zstring(wxString(str).ToUTF8()); -#elif defined ZSTRING_WIDE_CHAR +#ifdef FFS_WIN return str; +#elif defined FFS_LINUX + return Zstring(wxString(str).ToUTF8()); #endif } diff --git a/shared/system_constants.h b/shared/system_constants.h index 6877f5c7..7f34c467 100644 --- a/shared/system_constants.h +++ b/shared/system_constants.h @@ -16,12 +16,14 @@ namespace common // GLOBALS //------------------------------------------------ #ifdef FFS_WIN -const DefaultChar FILE_NAME_SEPARATOR = '\\'; -static const wxChar* const LINE_BREAK = wxT("\r\n"); //internal linkage +const Zchar FILE_NAME_SEPARATOR = '\\'; +const wxChar LINE_BREAK[] = wxT("\r\n"); //internal linkage #elif defined FFS_LINUX -const DefaultChar FILE_NAME_SEPARATOR = '/'; -static const wxChar* const LINE_BREAK = wxT("\n"); +const Zchar FILE_NAME_SEPARATOR = '/'; +const wxChar LINE_BREAK[] = wxT("\n"); #endif + +const char BYTE_ORDER_MARK_UTF8[] = "\xEF\xBB\xBF"; } diff --git a/shared/taskbar.cpp b/shared/taskbar.cpp index 61a1841b..f5f07c1e 100644 --- a/shared/taskbar.cpp +++ b/shared/taskbar.cpp @@ -12,17 +12,17 @@ #include <wx/msw/wrapwin.h> //includes "windows.h" using namespace util; +using namespace tbseven; namespace { bool windows7TaskbarAvailable() { - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + OSVERSIONINFO osvi = {}; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx(&osvi)) + if (::GetVersionEx(&osvi)) return osvi.dwMajorVersion > 6 || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 1); //task bar progress available with Windows 7 //XP has majorVersion == 5, minorVersion == 1 @@ -45,86 +45,77 @@ const std::wstring& getTaskBarDllName() return filename; } } +//######################################################################################################## -struct TaskbarProgress::Pimpl +class TaskbarProgress::Pimpl //throw (TaskbarNotAvailable) { - Pimpl() : tbHandle(0), - assocWindow(NULL), - init_(NULL), - release_(NULL), - setStatus_(NULL), - setProgress_(NULL) {} - - TaskbarSeven::TBHandle tbHandle; - void* assocWindow; - - TaskbarSeven::initFct init_; - TaskbarSeven::releaseFct release_; - TaskbarSeven::setStatusFct setStatus_; - TaskbarSeven::setProgressFct setProgress_; -}; - - -TaskbarProgress::TaskbarProgress(const wxTopLevelWindow& window) : pimpl_(new Pimpl) -{ - if (!windows7TaskbarAvailable()) - throw TaskbarNotAvailable(); +public: + Pimpl(const wxTopLevelWindow& window) : + assocWindow(window.GetHWND()), + setStatus_(util::getDllFun<SetStatusFct>( getTaskBarDllName(), setStatusFctName)), + setProgress_(util::getDllFun<SetProgressFct>(getTaskBarDllName(), setProgressFctName)) + { + if (!assocWindow || !setProgress_ || !setStatus_) + throw TaskbarNotAvailable(); - pimpl_->init_ = util::loadDllFunction<TaskbarSeven::initFct>( getTaskBarDllName(), TaskbarSeven::initFctName); - pimpl_->release_ = util::loadDllFunction<TaskbarSeven::releaseFct>( getTaskBarDllName(), TaskbarSeven::releaseFctName); - pimpl_->setProgress_ = util::loadDllFunction<TaskbarSeven::setProgressFct>(getTaskBarDllName(), TaskbarSeven::setProgressFctName); - pimpl_->setStatus_ = util::loadDllFunction<TaskbarSeven::setStatusFct>( getTaskBarDllName(), TaskbarSeven::setStatusFctName); + if (!windows7TaskbarAvailable()) + throw TaskbarNotAvailable(); + } - if ( !pimpl_->init_ || - !pimpl_->release_ || - !pimpl_->setProgress_ || - !pimpl_->setStatus_) - throw TaskbarNotAvailable(); + ~Pimpl() + { + setStatus(STATUS_NOPROGRESS); + } - pimpl_->tbHandle = pimpl_->init_(); - if (pimpl_->tbHandle == 0) - throw TaskbarNotAvailable(); + void setStatus(Status status) + { + TaskBarStatus tbSevenStatus = tbseven::STATUS_NORMAL; + switch (status) + { + case TaskbarProgress::STATUS_NOPROGRESS: + tbSevenStatus = tbseven::STATUS_NOPROGRESS; + break; + case TaskbarProgress::STATUS_INDETERMINATE: + tbSevenStatus = tbseven::STATUS_INDETERMINATE; + break; + case TaskbarProgress::STATUS_NORMAL: + tbSevenStatus = tbseven::STATUS_NORMAL; + break; + case TaskbarProgress::STATUS_ERROR: + tbSevenStatus = tbseven::STATUS_ERROR; + break; + case TaskbarProgress::STATUS_PAUSED: + tbSevenStatus = tbseven::STATUS_PAUSED; + break; + } + + setStatus_(assocWindow, tbSevenStatus); + } - pimpl_->assocWindow = window.GetHWND(); -} + void setProgress(size_t current, size_t total) + { + setProgress_(assocWindow, current, total); + } +private: + void* assocWindow; + const SetStatusFct setStatus_; + const SetProgressFct setProgress_; +}; +//######################################################################################################## -TaskbarProgress::~TaskbarProgress() -{ - setStatus(STATUS_NOPROGRESS); - pimpl_->release_(pimpl_->tbHandle); -} +TaskbarProgress::TaskbarProgress(const wxTopLevelWindow& window) : pimpl_(new Pimpl(window)) {} +TaskbarProgress::~TaskbarProgress() {} //std::auto_ptr ... void TaskbarProgress::setStatus(Status status) { - TaskbarSeven::TaskBarStatus tbSevenStatus = TaskbarSeven::STATUS_NORMAL; - switch (status) - { - case TaskbarProgress::STATUS_NOPROGRESS: - tbSevenStatus = TaskbarSeven::STATUS_NOPROGRESS; - break; - case TaskbarProgress::STATUS_INDETERMINATE: - tbSevenStatus = TaskbarSeven::STATUS_INDETERMINATE; - break; - case TaskbarProgress::STATUS_NORMAL: - tbSevenStatus = TaskbarSeven::STATUS_NORMAL; - break; - case TaskbarProgress::STATUS_ERROR: - tbSevenStatus = TaskbarSeven::STATUS_ERROR; - break; - case TaskbarProgress::STATUS_PAUSED: - tbSevenStatus = TaskbarSeven::STATUS_PAUSED; - break; - } - - pimpl_->setStatus_(pimpl_->tbHandle, pimpl_->assocWindow, tbSevenStatus); + pimpl_->setStatus(status); } - void TaskbarProgress::setProgress(size_t current, size_t total) { - pimpl_->setProgress_(pimpl_->tbHandle, pimpl_->assocWindow, current, total); + pimpl_->setProgress(current, total); } diff --git a/shared/taskbar.h b/shared/taskbar.h index 02d7324d..acf2d6da 100644 --- a/shared/taskbar.h +++ b/shared/taskbar.h @@ -39,7 +39,7 @@ public: void setProgress(size_t current, size_t total); private: - struct Pimpl; + class Pimpl; std::auto_ptr<Pimpl> pimpl_; }; diff --git a/shared/util.cpp b/shared/util.cpp index 9e0cb9d3..25c8c5e0 100644 --- a/shared/util.cpp +++ b/shared/util.cpp @@ -15,6 +15,7 @@ #include <stdexcept> #include "system_func.h" #include "check_exist.h" +#include "assert_static.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -99,32 +100,6 @@ wxString ffs_Impl::includeNumberSeparator(const wxString& number) } -template <class T> -void setDirectoryNameImpl(const wxString& dirname, T* txtCtrl, wxDirPickerCtrl* dirPicker) -{ - using namespace ffs3; - - txtCtrl->SetValue(dirname); - const Zstring dirFormatted = ffs3::getFormattedDirectoryName(wxToZ(dirname)); - - if (util::dirExists(dirFormatted, 200) == util::EXISTING_TRUE) //potentially slow network access: wait 200ms at most - dirPicker->SetPath(zToWx(dirFormatted)); -} - - -void ffs3::setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker) -{ - setDirectoryNameImpl(dirname, txtCtrl, dirPicker); -} - - -void ffs3::setDirectoryName(const wxString& dirname, wxComboBox* txtCtrl, wxDirPickerCtrl* dirPicker) -{ - txtCtrl->SetSelection(wxNOT_FOUND); - setDirectoryNameImpl(dirname, txtCtrl, dirPicker); -} - - void ffs3::scrollToBottom(wxScrolledWindow* scrWindow) { int height = 0; @@ -147,94 +122,128 @@ void ffs3::scrollToBottom(wxScrolledWindow* scrWindow) namespace { -inline -void writeTwoDigitNumber(size_t number, wxString& string) -{ - assert (number < 100); - - string += wxChar('0' + number / 10); - string += wxChar('0' + number % 10); -} - - -inline -void writeFourDigitNumber(size_t number, wxString& string) +#ifdef FFS_WIN +bool isVistaOrLater() { - assert (number < 10000); - - string += wxChar('0' + number / 1000); - number %= 1000; - string += wxChar('0' + number / 100); - number %= 100; - string += wxChar('0' + number / 10); - number %= 10; - string += wxChar('0' + number); + OSVERSIONINFO osvi = {}; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //symbolic links are supported starting with Vista + if (::GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1; Vista majorVersion == 6, dwMinorVersion == 0 + //overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; } +#endif } + wxString ffs3::utcTimeToLocalString(const wxLongLong& utcTime) { #ifdef FFS_WIN //convert ansi C time to FILETIME wxLongLong fileTimeLong(utcTime); - fileTimeLong += wxLongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s fileTimeLong *= 10000000; FILETIME lastWriteTimeUtc; lastWriteTimeUtc.dwLowDateTime = fileTimeLong.GetLo(); //GetLo() returns unsigned - lastWriteTimeUtc.dwHighDateTime = unsigned(fileTimeLong.GetHi()); //GetHi() returns signed - - - FILETIME localFileTime; - if (::FileTimeToLocalFileTime( //convert to local time - &lastWriteTimeUtc, //pointer to UTC file time to convert - &localFileTime //pointer to converted file time - ) == 0) - throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME: ") + - wxT("(") + wxULongLong(lastWriteTimeUtc.dwHighDateTime, lastWriteTimeUtc.dwLowDateTime).ToString() + wxT(") ") + - wxT("\n\n") + getLastErrorFormatted()).ToAscii())); - - if (localFileTime.dwHighDateTime > 0x7fffffff) - return _("Error"); //this actually CAN happen if UTC time is just below this border and ::FileTimeToLocalFileTime() adds 2 hours due to DST or whatever! - //Testcase (UTC): dateHigh = 2147483647 (=0x7fffffff) -> year 30000 - // dateLow = 4294967295 - - SYSTEMTIME time; - if (::FileTimeToSystemTime( - &localFileTime, //pointer to file time to convert - &time //pointer to structure to receive system time - ) == 0) - throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" local FILETIME -> SYSTEMTIME: ") + - wxT("(") + wxULongLong(localFileTime.dwHighDateTime, localFileTime.dwLowDateTime).ToString() + wxT(") ") + - wxT("\n\n") + getLastErrorFormatted()).ToAscii())); - - //assemble time string (performance optimized) -> note: performance argument may not be valid any more - wxString formattedTime; - formattedTime.reserve(20); - - writeFourDigitNumber(time.wYear, formattedTime); - formattedTime += wxChar('-'); - writeTwoDigitNumber(time.wMonth, formattedTime); - formattedTime += wxChar('-'); - writeTwoDigitNumber(time.wDay, formattedTime); - formattedTime += wxChar(' '); - formattedTime += wxChar(' '); - writeTwoDigitNumber(time.wHour, formattedTime); - formattedTime += wxChar(':'); - writeTwoDigitNumber(time.wMinute, formattedTime); - formattedTime += wxChar(':'); - writeTwoDigitNumber(time.wSecond, formattedTime); - - return formattedTime; + lastWriteTimeUtc.dwHighDateTime = static_cast<DWORD>(fileTimeLong.GetHi()); //GetHi() returns signed + + assert(fileTimeLong.GetHi() >= 0); + assert_static(sizeof(DWORD) == sizeof(long)); + assert_static(sizeof(long) == 4); + + SYSTEMTIME systemTimeLocal = {}; + + static const bool useNewLocalTimeCalculation = isVistaOrLater(); + if (useNewLocalTimeCalculation) //use DST setting from source date (like in Windows 7, see http://msdn.microsoft.com/en-us/library/ms724277(VS.85).aspx) + { + if (lastWriteTimeUtc.dwHighDateTime > 0x7FFFFFFF) + return _("Error"); + + SYSTEMTIME systemTimeUtc = {}; + if (!::FileTimeToSystemTime( + &lastWriteTimeUtc, //__in const FILETIME *lpFileTime, + &systemTimeUtc)) //__out LPSYSTEMTIME lpSystemTime + throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" FILETIME -> SYSTEMTIME: ") + + wxT("(") + wxULongLong(lastWriteTimeUtc.dwHighDateTime, lastWriteTimeUtc.dwLowDateTime).ToString() + wxT(") ") + + wxT("\n\n") + getLastErrorFormatted()).ToAscii())); + + if (!::SystemTimeToTzSpecificLocalTime( + NULL, //__in_opt LPTIME_ZONE_INFORMATION lpTimeZone, + &systemTimeUtc, //__in LPSYSTEMTIME lpUniversalTime, + &systemTimeLocal)) //__out LPSYSTEMTIME lpLocalTime + throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" SYSTEMTIME -> local SYSTEMTIME: ") + + wxT("(") + wxULongLong(lastWriteTimeUtc.dwHighDateTime, lastWriteTimeUtc.dwLowDateTime).ToString() + wxT(") ") + + wxT("\n\n") + getLastErrorFormatted()).ToAscii())); + } + else //use current DST setting (like in Windows 2000 and XP) + { + FILETIME fileTimeLocal = {}; + if (!::FileTimeToLocalFileTime( //convert to local time + &lastWriteTimeUtc, //pointer to UTC file time to convert + &fileTimeLocal)) //pointer to converted file time + throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME: ") + + wxT("(") + wxULongLong(lastWriteTimeUtc.dwHighDateTime, lastWriteTimeUtc.dwLowDateTime).ToString() + wxT(") ") + + wxT("\n\n") + getLastErrorFormatted()).ToAscii())); + + if (fileTimeLocal.dwHighDateTime > 0x7FFFFFFF) + return _("Error"); //this actually CAN happen if UTC time is just below this border and ::FileTimeToLocalFileTime() adds 2 hours due to DST or whatever! + //Testcase (UTC): dateHigh = 2147483647 (=0x7fffffff) -> year 30000 + // dateLow = 4294967295 + + if (!::FileTimeToSystemTime( + &fileTimeLocal, //pointer to file time to convert + &systemTimeLocal)) //pointer to structure to receive system time + throw std::runtime_error(std::string((wxString(_("Conversion error:")) + wxT(" local FILETIME -> local SYSTEMTIME: ") + + wxT("(") + wxULongLong(fileTimeLocal.dwHighDateTime, fileTimeLocal.dwLowDateTime).ToString() + wxT(") ") + + wxT("\n\n") + getLastErrorFormatted()).ToAscii())); + } + + /* + //assemble time string (performance optimized) -> note: performance argument is not valid anymore + + wxString formattedTime; + formattedTime.reserve(20); + + writeFourDigitNumber(time.wYear, formattedTime); + formattedTime += wxChar('-'); + writeTwoDigitNumber(time.wMonth, formattedTime); + formattedTime += wxChar('-'); + writeTwoDigitNumber(time.wDay, formattedTime); + formattedTime += wxChar(' '); + formattedTime += wxChar(' '); + writeTwoDigitNumber(time.wHour, formattedTime); + formattedTime += wxChar(':'); + writeTwoDigitNumber(time.wMinute, formattedTime); + formattedTime += wxChar(':'); + writeTwoDigitNumber(time.wSecond, formattedTime); + */ + const wxDateTime localTime(systemTimeLocal.wDay, + wxDateTime::Month(systemTimeLocal.wMonth - 1), + systemTimeLocal.wYear, + systemTimeLocal.wHour, + systemTimeLocal.wMinute, + systemTimeLocal.wSecond); #elif defined FFS_LINUX tm* timeinfo; const time_t fileTime = utcTime.ToLong(); timeinfo = localtime(&fileTime); //convert to local time - char buffer[50]; - strftime(buffer, 50, "%Y-%m-%d %H:%M:%S", timeinfo); - return zToWx(buffer); + /* + char buffer[50]; + ::strftime(buffer, 50, "%Y-%m-%d %H:%M:%S", timeinfo); + return zToWx(buffer); + */ + const wxDateTime localTime(timeinfo->tm_mday, + wxDateTime::Month(timeinfo->tm_mon), + 1900 + timeinfo->tm_year, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec); #endif + + return localTime.FormatDate() + wxT(" ") + localTime.FormatTime(); } diff --git a/shared/util.h b/shared/util.h index 5023c00b..2495838c 100644 --- a/shared/util.h +++ b/shared/util.h @@ -11,11 +11,10 @@ #include <wx/string.h> #include <wx/longlong.h> #include "../shared/global_func.h" - -class wxComboBox; -class wxTextCtrl; -class wxDirPickerCtrl; -class wxScrolledWindow; +#include <wx/textctrl.h> +#include <wx/filepicker.h> +#include <wx/combobox.h> +#include <wx/scrolwin.h> namespace ffs3 @@ -29,8 +28,6 @@ wxString formatPercentage(const wxLongLong& dividend, const wxLongLong& divisor) template <class NumberType> wxString numberToStringSep(NumberType number); //convert number to wxString including thousands separator -void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); -void setDirectoryName(const wxString& dirname, wxComboBox* txtCtrl, wxDirPickerCtrl* dirPicker); void scrollToBottom(wxScrolledWindow* scrWindow); wxString utcTimeToLocalString(const wxLongLong& utcTime); //throw std::runtime_error diff --git a/shared/zbase.h b/shared/zbase.h new file mode 100644 index 00000000..efaa103c --- /dev/null +++ b/shared/zbase.h @@ -0,0 +1,1162 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// +#ifndef Z_BASE_H_INCLUDED +#define Z_BASE_H_INCLUDED + +#include <cstddef> //size_t +#include <cctype> //isspace +#include <cwctype> //iswspace +#include <cassert> +#include <vector> +#include <sstream> +#include <algorithm> + + +/* +Allocator Policy: +----------------- + void* allocate(size_t size) //throw (std::bad_alloc) + void deallocate(void* ptr) +*/ +class AllocatorFreeStore //same performance characterisics like malloc()/free() +{ +public: + static void* allocate(size_t size) //throw (std::bad_alloc) + { + return ::operator new(size); + } + + static void deallocate(void* ptr) + { + ::operator delete(ptr); + } +}; + + +/* +Storage Policy: +--------------- +template <typename T, //Character Type + class AP> //Allocator Policy + + T* create(size_t size) + T* create(size_t size, size_t minCapacity) + T* clone(T* ptr) + void destroy(T* ptr) + bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + size_t length(const T* ptr) + void setLength(T* ptr, size_t newLength) +*/ + +template <typename T, //Character Type + class AP> //Allocator Policy +class StorageDeepCopy : public AP +{ +protected: + ~StorageDeepCopy() {} + + static T* create(size_t size) + { + return create(size, size); + } + + static T* create(size_t size, size_t minCapacity) + { + const size_t newCapacity = calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); + assert(minCapacity >= size); + + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + + newDescr->length = size; + newDescr->capacity = newCapacity; + + return reinterpret_cast<T*>(newDescr + 1); + } + + static T* clone(T* ptr) + { + T* newData = create(length(ptr)); + std::copy(ptr, ptr + length(ptr) + 1, newData); + return newData; + } + + static void destroy(T* ptr) + { + AP::deallocate(descr(ptr)); + } + + static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + { + return minCapacity <= descr(ptr)->capacity; + } + + static size_t length(const T* ptr) + { + return descr(ptr)->length; + } + + static void setLength(T* ptr, size_t newLength) + { + assert(canWrite(ptr, newLength)); + descr(ptr)->length = newLength; + } + +private: + struct Descriptor + { + size_t length; + size_t capacity; //allocated size without null-termination + }; + + static Descriptor* descr(T* ptr) + { + return reinterpret_cast<Descriptor*>(ptr) - 1; + } + + static const Descriptor* descr(const T* ptr) + { + return reinterpret_cast<const Descriptor*>(ptr) - 1; + } + + static size_t calcCapacity(size_t length) + { + return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation + } +}; + + +template <typename T, //Character Type + class AP> //Allocator Policy +class StorageRefCount : public AP +{ +protected: + ~StorageRefCount() {} + + static T* create(size_t size) + { + return create(size, size); + } + + static T* create(size_t size, size_t minCapacity) + { + const size_t newCapacity = calcCapacity(minCapacity); + assert(newCapacity >= minCapacity); + assert(minCapacity >= size); + + Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(T))); + + newDescr->refCount = 1; + newDescr->length = size; + newDescr->capacity = newCapacity; + + return reinterpret_cast<T*>(newDescr + 1); + } + + static T* clone(T* ptr) + { + assert(descr(ptr)->refCount > 0); + ++descr(ptr)->refCount; + return ptr; + } + + static void destroy(T* ptr) + { + if (--descr(ptr)->refCount == 0) + AP::deallocate(descr(ptr)); + } + + static bool canWrite(const T* ptr, size_t minCapacity) //needs to be checked before writing to "ptr" + { + assert(descr(ptr)->refCount > 0); + return descr(ptr)->refCount == 1 && minCapacity <= descr(ptr)->capacity; + } + + static size_t length(const T* ptr) + { + return descr(ptr)->length; + } + + static void setLength(T* ptr, size_t newLength) + { + assert(canWrite(ptr, newLength)); + descr(ptr)->length = newLength; + } + +private: + struct Descriptor + { + size_t refCount; + size_t length; + size_t capacity; //allocated size without null-termination + }; + + static Descriptor* descr(T* ptr) + { + return reinterpret_cast<Descriptor*>(ptr) - 1; + } + + static const Descriptor* descr(const T* ptr) + { + return reinterpret_cast<const Descriptor*>(ptr) - 1; + } + + static size_t calcCapacity(size_t length) + { + return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation + } +}; + + +template <class T, //Character Type + template <class, class> class SP = StorageRefCount, //Storage Policy + class AP = AllocatorFreeStore> //Allocator Policy +class Zbase : public SP<T, AP> +{ +public: + Zbase(); + Zbase(T source); + Zbase(const T* source); + Zbase(const T* source, size_t length); + Zbase(const Zbase& source); + ~Zbase(); + + operator const T*() const; //implicit conversion to C-string + + //STL accessors + const T* begin() const; + const T* end() const; + T* begin(); + T* end(); + + //wxString-like functions + bool StartsWith(const Zbase& prefix) const; + bool StartsWith(const T* prefix) const; + bool StartsWith(T prefix) const; + bool EndsWith(const Zbase& postfix) const; + bool EndsWith(const T* postfix) const; + bool EndsWith(T postfix) const; + Zbase& Truncate(size_t newLen); + Zbase& Replace(const T* old, const T* replacement, bool replaceAll = true); + Zbase AfterLast( T ch) const; //returns the whole string if "ch" not found + Zbase BeforeLast( T ch) const; //returns empty string if "ch" not found + Zbase AfterFirst( T ch) const; //returns empty string if "ch" not found + Zbase BeforeFirst(T ch) const; //returns the whole string if "ch" not found + Zbase& Trim(bool fromLeft = true, bool fromRight = true); + std::vector<Zbase> Split(T delimiter) const; + + //std::string functions + size_t length() const; + size_t size() const; + const T* c_str() const; //C-string format with NULL-termination + const T* data() const; //internal representation, NULL-termination not guaranteed + const T operator[](size_t pos) const; + Zbase substr(size_t pos = 0, size_t len = npos) const; + bool empty() const; + void clear(); + size_t find(const Zbase& str, size_t pos = 0) const; // + size_t find(const T* str, size_t pos = 0) const; //returns "npos" if not found + size_t find(T ch, size_t pos = 0) const; // + size_t rfind(T ch, size_t pos = npos) const; // + Zbase& replace(size_t pos1, size_t n1, const T* str, size_t n2); + void reserve(size_t minCapacity); + Zbase& assign(const T* source, size_t len); + void resize(size_t newSize, T fillChar = 0); + void swap(Zbase& other); + + //number conversion + template <class N> static Zbase fromNumber(N number); + template <class N> N toNumber() const; + + Zbase& operator=(const Zbase& source); + Zbase& operator=(const T* source); + Zbase& operator=(T source); + Zbase& operator+=(const Zbase& other); + Zbase& operator+=(const T* other); + Zbase& operator+=(T ch); + + static const size_t npos = static_cast<size_t>(-1); + +private: + Zbase(int); //detect usage errors + Zbase& operator=(int); // + + T* rawStr; +}; + +template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> bool operator< (const T* lhs, const Zbase<T, SP, AP>& rhs); + +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+( T lhs, const Zbase<T, SP, AP>& rhs); +template <class T, template <class, class> class SP, class AP> const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//################################# inline implementation ######################################## +namespace z_impl +{ +//-------------C-string helper functions --------------------------------------------------------- +template <class T> +inline +size_t cStringLength(const T* input) //strlen() +{ + const T* iter = input; + while (*iter != 0) + ++iter; + return iter - input; +} +} + + +//-------------------------------------------------------------------------------------------------- +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase() +{ + //resist the temptation to avoid this allocation by referening a static global: NO performance advantage, MT issues! + rawStr = this->create(0); + rawStr[0] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(T source) +{ + rawStr = this->create(1); + rawStr[0] = source; + rawStr[1] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const T* source) +{ + const size_t sourceLen = z_impl::cStringLength(source); + rawStr = this->create(sourceLen); + std::copy(source, source + sourceLen + 1, rawStr); //include null-termination +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const T* source, size_t sourceLen) +{ + rawStr = this->create(sourceLen); + std::copy(source, source + sourceLen, rawStr); + rawStr[sourceLen] = 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::Zbase(const Zbase<T, SP, AP>& source) +{ + rawStr = this->clone(source.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::~Zbase() +{ + this->destroy(rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>::operator const T*() const +{ + return rawStr; +} + + +// get all characters after the last occurence of ch +// (returns the whole string if ch not found) +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::AfterLast(T ch) const +{ + const size_t pos = rfind(ch, npos); + if (pos != npos ) + return Zbase(rawStr + pos + 1, length() - pos - 1); + else + return *this; +} + + +// get all characters before the last occurence of ch +// (returns empty string if ch not found) +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::BeforeLast(T ch) const +{ + const size_t pos = rfind(ch, npos); + if (pos != npos) + return Zbase(rawStr, pos); //data is non-empty string in this context: else ch would not have been found! + else + return Zbase(); +} + + +//returns empty string if ch not found +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::AfterFirst(T ch) const +{ + const size_t pos = find(ch, 0); + if (pos != npos) + return Zbase(rawStr + pos + 1, length() - pos - 1); + else + return Zbase(); + +} + +//returns the whole string if ch not found +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::BeforeFirst(T ch) const +{ + const size_t pos = find(ch, 0); + if (pos != npos) + return Zbase(rawStr, pos); //data is non-empty string in this context: else ch would not have been found! + else + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(const T* prefix) const +{ + const size_t pfLength = z_impl::cStringLength(prefix); + if (length() < pfLength) + return false; + + return std::equal(rawStr, rawStr + pfLength, + prefix); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(T prefix) const +{ + return length() != 0 && operator[](0) == prefix; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::StartsWith(const Zbase<T, SP, AP>& prefix) const +{ + if (length() < prefix.length()) + return false; + + return std::equal(rawStr, rawStr + prefix.length(), + prefix.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(const T* postfix) const +{ + const size_t pfLength = z_impl::cStringLength(postfix); + if (length() < pfLength) + return false; + + const T* cmpBegin = rawStr + length() - pfLength; + return std::equal(cmpBegin, cmpBegin + pfLength, + postfix); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(T postfix) const +{ + const size_t len = length(); + return len != 0 && operator[](len - 1) == postfix; +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::EndsWith(const Zbase<T, SP, AP>& postfix) const +{ + if (length() < postfix.length()) + return false; + + const T* cmpBegin = rawStr + length() - postfix.length(); + return std::equal(cmpBegin, cmpBegin + postfix.length(), + postfix.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Truncate(size_t newLen) +{ + if (newLen < length()) + { + if (canWrite(rawStr, newLen)) + { + rawStr[newLen] = 0; + setLength(rawStr, newLen); + } + else + *this = Zbase(rawStr, newLen); + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(const Zbase& str, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); //respect embedded 0 + const T* iter = std::search(begin() + pos, thisEnd, + str.begin(), str.end()); + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(const T* str, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); //respect embedded 0 + const T* iter = std::search(begin() + pos, thisEnd, + str, str + z_impl::cStringLength(str)); + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::find(T ch, size_t pos) const +{ + assert(pos <= length()); + const T* thisEnd = end(); + const T* iter = std::find(begin() + pos, thisEnd, ch); //respect embedded 0 + return iter == thisEnd ? npos : iter - begin(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::rfind(T ch, size_t pos) const +{ + assert(pos == npos || pos <= length()); + + const size_t thisLen = length(); + if (thisLen == 0) return npos; + pos = std::min(thisLen - 1, pos); //handle "npos" and "pos == length()" implicitly + + while (rawStr[pos] != ch) //pos points to last char of the string + { + if (pos == 0) + return npos; + --pos; + } + return pos; +} + + +template <class T, template <class, class> class SP, class AP> +Zbase<T, SP, AP>& Zbase<T, SP, AP>::replace(size_t pos1, size_t n1, const T* str, size_t n2) +{ + assert(str < rawStr || rawStr + length() < str); //str mustn't point to data in this string + assert(pos1 + n1 <= length()); + + const size_t oldLen = length(); + if (oldLen == 0) + return *this = Zbase(str, n2); + + const size_t newLen = oldLen - n1 + n2; + + if (canWrite(rawStr, newLen)) + { + if (n1 < n2) //move remainder right -> std::copy_backward + { + std::copy_backward(rawStr + pos1 + n1, rawStr + oldLen + 1, rawStr + newLen + 1); //include null-termination + setLength(rawStr, newLen); + } + else if (n1 > n2) //shift left -> std::copy + { + std::copy(rawStr + pos1 + n1, rawStr + oldLen + 1, rawStr + pos1 + n2); //include null-termination + setLength(rawStr, newLen); + } + + std::copy(str, str + n2, rawStr + pos1); + } + else + { + //copy directly into new string + T* const newStr = this->create(newLen); + + std::copy(rawStr, rawStr + pos1, newStr); + std::copy(str, str + n2, newStr + pos1); + std::copy(rawStr + pos1 + n1, rawStr + oldLen + 1, newStr + pos1 + n2); //include null-termination + + destroy(rawStr); + rawStr = newStr; + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Replace(const T* old, const T* replacement, bool replaceAll) +{ + const size_t oldLen = z_impl::cStringLength(old); + const size_t replacementLen = z_impl::cStringLength(replacement); + + size_t pos = 0; + while ((pos = find(old, pos)) != npos) + { + replace(pos, oldLen, replacement, replacementLen); + pos += replacementLen; //move past the string that was replaced + + if (!replaceAll) + break; + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::resize(size_t newSize, T fillChar) +{ + if (canWrite(rawStr, newSize)) + { + if (length() < newSize) + std::fill(rawStr + length(), rawStr + newSize, fillChar); + rawStr[newSize] = 0; + setLength(rawStr, newSize); //keep after call to length() + } + else + { + T* newStr = this->create(newSize); + newStr[newSize] = 0; + + if (length() < newSize) + { + std::copy(rawStr, rawStr + length(), newStr); + std::fill(newStr + length(), newStr + newSize, fillChar); + } + else + std::copy(rawStr, rawStr + newSize, newStr); + + destroy(rawStr); + rawStr = newStr; + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return lhs.length() == rhs.length() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); //respect embedded 0 +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return lhs.length() == z_impl::cStringLength(rhs) && std::equal(lhs.begin(), lhs.end(), rhs); //respect embedded 0 +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator==(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return operator==(rhs, lhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator!=(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return !operator==(lhs, rhs); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 + rhs.begin(), rhs.end()); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 + rhs, rhs + z_impl::cStringLength(rhs)); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool operator<(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return std::lexicographical_compare(lhs, lhs + z_impl::cStringLength(lhs), //respect embedded 0 + rhs.begin(), rhs.end()); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::length() const +{ + return SP<T, AP>::length(rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +size_t Zbase<T, SP, AP>::size() const +{ + return length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::c_str() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::data() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T Zbase<T, SP, AP>::operator[](size_t pos) const +{ + assert(pos < length()); + return rawStr[pos]; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::begin() const +{ + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const T* Zbase<T, SP, AP>::end() const +{ + return rawStr + length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +T* Zbase<T, SP, AP>::begin() +{ + reserve(length()); + return rawStr; +} + + +template <class T, template <class, class> class SP, class AP> +inline +T* Zbase<T, SP, AP>::end() +{ + return begin() + length(); +} + + +template <class T, template <class, class> class SP, class AP> +inline +bool Zbase<T, SP, AP>::empty() const +{ + return length() == 0; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::clear() +{ + if (!empty()) + { + if (canWrite(rawStr, 0)) + { + rawStr[0] = 0; //keep allocated memory + setLength(rawStr, 0); // + } + else + *this = Zbase(); + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, const T* rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const T* lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(T lhs, const Zbase<T, SP, AP>& rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +const Zbase<T, SP, AP> operator+(const Zbase<T, SP, AP>& lhs, T rhs) +{ + return Zbase<T, SP, AP>(lhs) += rhs; +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::swap(Zbase<T, SP, AP>& other) +{ + std::swap(rawStr, other.rawStr); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::substr(size_t pos, size_t len) const +{ + assert(pos + (len == npos ? 0 : len) <= length()); + return Zbase(rawStr + pos, len == npos ? length() - pos : len); +} + + +template <class T, template <class, class> class SP, class AP> +inline +void Zbase<T, SP, AP>::reserve(size_t minCapacity) //make unshared and check capacity +{ + if (!canWrite(rawStr, minCapacity)) + { + //allocate a new string + T* newStr = create(length(), std::max(minCapacity, length())); //reserve() must NEVER shrink the string: logical const! + std::copy(rawStr, rawStr + length() + 1, newStr); //include NULL-termination + + destroy(rawStr); + rawStr = newStr; + } +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::assign(const T* source, size_t len) +{ + if (canWrite(rawStr, len)) + { + std::copy(source, source + len, rawStr); + rawStr[len] = 0; //include null-termination + setLength(rawStr, len); + } + else + *this = Zbase(source, len); + + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const Zbase<T, SP, AP>& source) +{ + Zbase(source).swap(*this); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(const T* source) +{ + return assign(source, z_impl::cStringLength(source)); +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator=(T source) +{ + if (canWrite(rawStr, 1)) + { + rawStr[0] = source; + rawStr[1] = 0; //include null-termination + setLength(rawStr, 1); + } + else + *this = Zbase(source); + + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(const Zbase<T, SP, AP>& other) +{ + const size_t thisLen = length(); + const size_t otherLen = other.length(); + reserve(thisLen + otherLen); //make unshared and check capacity + + std::copy(other.rawStr, other.rawStr + otherLen + 1, rawStr + thisLen); //include null-termination + setLength(rawStr, thisLen + otherLen); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(const T* other) +{ + const size_t thisLen = length(); + const size_t otherLen = z_impl::cStringLength(other); + reserve(thisLen + otherLen); //make unshared and check capacity + + std::copy(other, other + otherLen + 1, rawStr + thisLen); //include null-termination + setLength(rawStr, thisLen + otherLen); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +inline +Zbase<T, SP, AP>& Zbase<T, SP, AP>::operator+=(T ch) +{ + const size_t thisLen = length(); + reserve(thisLen + 1); //make unshared and check capacity + rawStr[thisLen] = ch; + rawStr[thisLen + 1] = 0; + setLength(rawStr, thisLen + 1); + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +template <class N> +inline +Zbase<T, SP, AP> Zbase<T, SP, AP>::fromNumber(N number) +{ + std::basic_ostringstream<T> ss; + ss << number; + return Zbase<T, SP, AP>(ss.str().c_str()); +} + + +template <class T, template <class, class> class SP, class AP> +template <class N> +inline +N Zbase<T, SP, AP>::toNumber() const +{ + std::basic_istringstream<T> ss(std::basic_string<T>(rawStr)); + T number = 0; + ss >> number; + return number; +} + + +namespace z_impl +{ +template <class T> +bool cStringWhiteSpace(T ch); + +template <> +inline +bool cStringWhiteSpace(char ch) +{ + return std::isspace(static_cast<unsigned char>(ch)) != 0; //some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA'); but no issue with newer versions of MSVC +} + + +template <> +inline +bool cStringWhiteSpace(wchar_t ch) +{ + return std::iswspace(ch) != 0; //some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA'); but no issue with newer versions of MSVC +} +} + + +template <class T, template <class, class> class SP, class AP> +Zbase<T, SP, AP>& Zbase<T, SP, AP>::Trim(bool fromLeft, bool fromRight) +{ + assert(fromLeft || fromRight); + + const T* newBegin = rawStr; + const T* newEnd = rawStr + length(); + + if (fromRight) + while (newBegin != newEnd && z_impl::cStringWhiteSpace(newEnd[-1])) + --newEnd; + + if (fromLeft) + while (newBegin != newEnd && z_impl::cStringWhiteSpace(*newBegin)) + ++newBegin; + + const size_t newLength = newEnd - newBegin; + if (newLength != length()) + { + if (canWrite(rawStr, newLength)) + { + std::copy(newBegin, newBegin + newLength, rawStr); //shift left => std::copy, shift right std::copy_backward + rawStr[newLength] = 0; + setLength(rawStr, newLength); + } + else + *this = Zbase(newBegin, newLength); + } + return *this; +} + + +template <class T, template <class, class> class SP, class AP> +std::vector<Zbase<T, SP, AP> > Zbase<T, SP, AP>::Split(T delimiter) const +{ + std::vector<Zbase> output; + + const size_t thisLen = length(); + size_t startPos = 0; + for (;;) //make MSVC happy + { + size_t endPos = find(delimiter, startPos); + if (endPos == npos) + endPos = thisLen; + + if (startPos != endPos) //do not add empty strings + { + Zbase newEntry = substr(startPos, endPos - startPos); + newEntry.Trim(); //remove whitespace characters + + if (!newEntry.empty()) + output.push_back(newEntry); + } + if (endPos == thisLen) + break; + + startPos = endPos + 1; //skip delimiter + } + + return output; +} + + +#endif //Z_BASE_H_INCLUDED diff --git a/shared/zstring.cpp b/shared/zstring.cpp index 39f1898d..1a05831d 100644 --- a/shared/zstring.cpp +++ b/shared/zstring.cpp @@ -9,56 +9,79 @@ #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" +#undef min +#undef max #include "dll_loader.h" #include <boost/scoped_array.hpp> #endif //FFS_WIN #ifndef NDEBUG #include <wx/string.h> +#include <iostream> +#include <cstdlib> #endif #ifndef NDEBUG -AllocationCount::~AllocationCount() +LeakChecker::~LeakChecker() { if (activeStrings.size() > 0) -#ifdef FFS_WIN { int rowCount = 0; - wxString leakingStrings; - for (std::set<const DefaultChar*>::const_iterator i = activeStrings.begin(); - i != activeStrings.end() && ++rowCount <= 10; + std::string leakingStrings; + + for (VoidPtrSizeMap::const_iterator i = activeStrings.begin(); + i != activeStrings.end() && ++rowCount <= 20; ++i) - { - leakingStrings += wxT("\""); - leakingStrings += *i; - leakingStrings += wxT("\"\n"); - } + leakingStrings += "\"" + rawMemToString(i->first, i->second) + "\"\n"; - MessageBox(NULL, wxString(wxT("Memory leak detected!")) + wxT("\n\n") - + wxT("Candidates:\n") + leakingStrings, - wxString::Format(wxT("%u"), activeStrings.size()), 0); - } + const std::string message = std::string("Memory leak detected!") + "\n\n" + + "Candidates:\n" + leakingStrings; +#ifdef FFS_WIN + MessageBoxA(NULL, message.c_str(), "Error", 0); #else - throw std::logic_error("Memory leak!"); + std::cerr << message; + std::abort(); #endif + } } -AllocationCount& AllocationCount::getInstance() +LeakChecker& LeakChecker::instance() { - static AllocationCount global; - return global; + static LeakChecker inst; + return inst; +} + + +std::string LeakChecker::rawMemToString(const void* ptr, size_t size) +{ + std::string output = std::string(reinterpret_cast<const char*>(ptr), size); + output.erase(std::remove(output.begin(), output.end(), 0), output.end()); //remove intermediate 0-termination + if (output.size() > 100) + output.resize(100); + return output; +} + + +void LeakChecker::reportProblem(const std::string& message) //throw (std::logic_error) +{ +#ifdef FFS_WIN + ::MessageBoxA(NULL, message.c_str(), "Error", 0); +#else + std::cerr << message; +#endif + throw std::logic_error("Memory leak! " + message); } #endif //NDEBUG + #ifdef FFS_WIN namespace { bool hasInvariantLocale() { - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + OSVERSIONINFO osvi = {}; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //invariant locale has been introduced with XP @@ -75,13 +98,13 @@ bool hasInvariantLocale() //warning: LOCALE_INVARIANT is NOT available with Windows 2000, so we have to make yet another distinction... -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 +const LCID ZSTRING_INVARIANT_LOCALE = hasInvariantLocale() ? + LOCALE_INVARIANT : + MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); //see: http://msdn.microsoft.com/en-us/goglobal/bb688122.aspx +} -inline -int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB) +int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB) { //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" @@ -91,16 +114,15 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size LPCWSTR lpString2, int cchCount2, BOOL bIgnoreCase); - static const CompareStringOrdinalFunc ordinalCompare = util::loadDllFunction<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); + static const CompareStringOrdinalFunc ordinalCompare = util::getDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); if (ordinalCompare != NULL) //this additional test has no noticeable performance impact { - const int rv = (*ordinalCompare)( - a, //pointer to first string - static_cast<int>(sizeA), //size, in bytes or characters, of first string - b, //pointer to second string - static_cast<int>(sizeB), //size, in bytes or characters, of second string - true); //ignore case + const int rv = ordinalCompare(a, //pointer to first string + static_cast<int>(sizeA), //size, in bytes or characters, of first string + b, //pointer to second string + static_cast<int>(sizeB), //size, in bytes or characters, of second string + true); //ignore case if (rv == 0) throw std::runtime_error("Error comparing strings (ordinal)!"); else @@ -114,7 +136,7 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size const size_t minSize = std::min(sizeA, sizeB); if (minSize == 0) //LCMapString does not allow input sizes of 0! - return static_cast<int>(sizeA - sizeB); + return static_cast<int>(sizeA) - static_cast<int>(sizeB); int rv = 0; //always initialize... if (minSize <= 5000) //performance optimization: stack @@ -123,7 +145,7 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size wchar_t bufferB[5000]; if (::LCMapString( //faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString() - invariantLocale, //__in LCID Locale, + ZSTRING_INVARIANT_LOCALE, //__in LCID Locale, LCMAP_UPPERCASE, //__in DWORD dwMapFlags, a, //__in LPCTSTR lpSrcStr, static_cast<int>(minSize), //__in int cchSrc, @@ -132,7 +154,7 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size ) == 0) throw std::runtime_error("Error comparing strings! (LCMapString)"); - if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, b, static_cast<int>(minSize), bufferB, 5000) == 0) + if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, static_cast<int>(minSize), bufferB, 5000) == 0) throw std::runtime_error("Error comparing strings! (LCMapString)"); rv = ::wmemcmp(bufferA, bufferB, minSize); @@ -142,17 +164,17 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size 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, static_cast<int>(minSize), bufferA.get(), static_cast<int>(minSize)) == 0) + if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, a, static_cast<int>(minSize), bufferA.get(), static_cast<int>(minSize)) == 0) throw std::runtime_error("Error comparing strings! (LCMapString: FS)"); - if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, b, static_cast<int>(minSize), bufferB.get(), static_cast<int>(minSize)) == 0) + if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, static_cast<int>(minSize), bufferB.get(), static_cast<int>(minSize)) == 0) throw std::runtime_error("Error comparing strings! (LCMapString: FS)"); rv = ::wmemcmp(bufferA.get(), bufferB.get(), minSize); } return rv == 0 ? - static_cast<int>(sizeA - sizeB) : + static_cast<int>(sizeA) - static_cast<int>(sizeB) : rv; } @@ -169,429 +191,50 @@ int compareFilenamesWin32(const wchar_t* a, const wchar_t* b, size_t sizeA, size // else // return rv - 2; //convert to C-style string compare result } -} -#endif - - -int cmpFileName(const Zstring& lhs, const Zstring& rhs) -{ -#ifdef FFS_WIN - return ::compareFilenamesWin32(lhs.c_str(), rhs.c_str(), lhs.length(), rhs.length()); //way faster than wxString::CmpNoCase() -#elif defined FFS_LINUX - return ::strcmp(lhs.c_str(), rhs.c_str()); -#endif -} - - -int cmpFileName(const Zstring& lhs, const DefaultChar* rhs) -{ -#ifdef FFS_WIN - return ::compareFilenamesWin32(lhs.c_str(), rhs, lhs.length(), ::wcslen(rhs)); //way faster than wxString::CmpNoCase() -#elif defined FFS_LINUX -return ::strcmp(lhs.c_str(), rhs); -#endif -} - - -int cmpFileName(const DefaultChar* lhs, const DefaultChar* rhs) -{ -#ifdef FFS_WIN - return ::compareFilenamesWin32(lhs, rhs, ::wcslen(lhs), ::wcslen(rhs)); //way faster than wxString::CmpNoCase() -#elif defined FFS_LINUX - return ::strcmp(lhs, rhs); -#endif -} - - -Zstring& Zstring::Replace(const DefaultChar* old, const DefaultChar* replacement, bool replaceAll) -{ - const size_t oldLen = defaultLength(old); - const size_t replacementLen = defaultLength(replacement); - - size_t pos = 0; - for (;;) - { - pos = find(old, pos); - if (pos == npos) - break; - - replace(pos, oldLen, replacement, replacementLen); - pos += replacementLen; //move past the string that was replaced - - // stop now? - if (!replaceAll) - break; - } - return *this; -} - - -bool Zstring::matchesHelper(const DefaultChar* string, const DefaultChar* mask) -{ - for (DefaultChar ch; (ch = *mask) != 0; ++mask, ++string) - { - switch (ch) - { - case DefaultChar('?'): - if (*string == 0) - return false; - break; - - case DefaultChar('*'): - //advance to next non-*/? char - do - { - ++mask; - ch = *mask; - } - while (ch == DefaultChar('*') || ch == DefaultChar('?')); - //if match ends with '*': - if (ch == 0) - return true; - - ++mask; - while ((string = defaultStrFind(string, ch)) != NULL) - { - ++string; - if (matchesHelper(string, mask)) - return true; - } - return false; - - default: - if (*string != ch) - return false; - } - } - return *string == 0; -} - - -bool Zstring::Matches(const DefaultChar* mask) const -{ - return matchesHelper(c_str(), mask); -} - - -bool Zstring::Matches(const DefaultChar* name, const DefaultChar* mask) -{ - return matchesHelper(name, mask); -} - - -namespace -{ -#ifdef ZSTRING_CHAR -inline -bool defaultIsWhiteSpace(char ch) -{ - // some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA') => exclude char(128) to char(255) - return (static_cast<unsigned char>(ch) < 128) && isspace(static_cast<unsigned char>(ch)) != 0; -} - -#elif defined ZSTRING_WIDE_CHAR -inline -bool defaultIsWhiteSpace(wchar_t ch) -{ - // some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA') => exclude char(128) to char(255) - return (ch < 128 || ch > 255) && iswspace(ch) != 0; -} -#endif -} - - -Zstring& Zstring::Trim(bool fromRight) -{ - const size_t thisLen = length(); - if (thisLen == 0) - return *this; - - DefaultChar* const strBegin = data(); - - if (fromRight) - { - const DefaultChar* cursor = strBegin + thisLen - 1; - while (cursor != strBegin - 1 && defaultIsWhiteSpace(*cursor)) //break when pointing one char further than last skipped element - --cursor; - ++cursor; - - const size_t newLength = cursor - strBegin; - if (newLength != thisLen) - { - if (descr->refCount > 1) //allocate new string - *this = Zstring(strBegin, newLength); - else //overwrite this string - { - descr->length = newLength; - strBegin[newLength] = 0; - } - } - } - else - { - const DefaultChar* cursor = strBegin; - const DefaultChar* const strEnd = strBegin + thisLen; - while (cursor != strEnd && defaultIsWhiteSpace(*cursor)) - ++cursor; - - const size_t diff = cursor - strBegin; - if (diff) - { - if (descr->refCount > 1) //allocate new string - *this = Zstring(cursor, thisLen - diff); - else - { - //overwrite this string - ::memmove(strBegin, cursor, (thisLen - diff + 1) * sizeof(DefaultChar)); //note: do not simply let data point to different location: this corrupts reserve()! - descr->length -= diff; - } - } - } - - return *this; -} - - -std::vector<Zstring> Zstring::Tokenize(const DefaultChar delimiter) const -{ - std::vector<Zstring> output; - - const size_t thisLen = length(); - size_t indexStart = 0; - for (;;) - { - size_t indexEnd = find(delimiter, indexStart); - if (indexEnd == Zstring::npos) - indexEnd = thisLen; - - if (indexStart != indexEnd) //do not add empty strings - { - Zstring newEntry = substr(indexStart, indexEnd - indexStart); - newEntry.Trim(true); //remove whitespace characters from right - newEntry.Trim(false); //remove whitespace characters from left - - if (!newEntry.empty()) - output.push_back(newEntry); - } - if (indexEnd == thisLen) - break; - - indexStart = indexEnd + 1; //delimiter is a single character - } - - return output; -} -#ifdef FFS_WIN -Zstring& Zstring::MakeUpper() +void z_impl::makeUpperCaseWin(wchar_t* str, size_t size) { - const size_t thisLen = length(); - if (thisLen == 0) - return *this; - - reserve(thisLen); //make unshared + if (size == 0) //LCMapString does not allow input sizes of 0! + return; //use Windows' upper case conversion: faster than ::CharUpper() - if (::LCMapString(invariantLocale, LCMAP_UPPERCASE, data(), static_cast<int>(thisLen), data(), static_cast<int>(thisLen)) == 0) + if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, str, static_cast<int>(size), str, static_cast<int>(size)) == 0) throw std::runtime_error("Error converting to upper case! (LCMapString)"); - - return *this; -} -#endif - - -//############################################################### -//std::string functions -Zstring Zstring::substr(size_t pos, size_t len) const -{ - if (len == npos) - { - assert(pos <= length()); - return Zstring(c_str() + pos, length() - pos); //reference counting not used: different length - } - else - { - assert(length() - pos >= len); - return Zstring(c_str() + pos, len); - } } -size_t Zstring::rfind(DefaultChar ch, size_t pos) const -{ - const size_t thisLen = length(); - if (thisLen == 0) - return npos; - - if (pos == npos) - pos = thisLen - 1; - else - assert(pos <= length()); - - do //pos points to last char of the string - { - if (c_str()[pos] == ch) - return pos; - } - while (--pos != static_cast<size_t>(-1)); - - return npos; -} - - -Zstring& Zstring::replace(size_t pos1, size_t n1, const DefaultChar* str, size_t n2) -{ - assert(str < c_str() || c_str() + length() < str); //str mustn't point to data in this string - assert(n1 <= length() - pos1); - - const size_t oldLen = length(); - if (oldLen == 0) - { - assert(pos1 == 0 && n1 == 0); - return *this = Zstring(str, n2); - } - - const size_t newLen = oldLen - n1 + n2; - if (newLen > oldLen || descr->refCount > 1) - { - //allocate a new string - StringDescriptor* newDescr = allocate(newLen); - - //assemble new string with replacement - DefaultChar* const newData = reinterpret_cast<DefaultChar*>(newDescr + 1); - ::memcpy(newData, c_str(), pos1 * sizeof(DefaultChar)); - ::memcpy(newData + pos1, str, n2 * sizeof(DefaultChar)); - ::memcpy(newData + pos1 + n2, c_str() + pos1 + n1, (oldLen - pos1 - n1) * sizeof(DefaultChar)); - newData[newLen] = 0; - - decRef(); - descr = newDescr; - } - else //overwrite current string: case "n2 == 0" is handled implicitly - { - ::memcpy(data() + pos1, str, n2 * sizeof(DefaultChar)); - if (newLen < oldLen) - { - ::memmove(data() + pos1 + n2, data() + pos1 + n1, (oldLen - pos1 - n1) * sizeof(DefaultChar)); - data()[newLen] = 0; - descr->length = newLen; - } - } - - return *this; -} - - -Zstring& Zstring::operator=(const DefaultChar* source) -{ - const size_t sourceLen = defaultLength(source); - - if (descr->refCount > 1 || descr->capacity < sourceLen) //allocate new string - *this = Zstring(source, sourceLen); - else - { - //overwrite this string - ::memcpy(data(), source, (sourceLen + 1) * sizeof(DefaultChar)); //include null-termination - descr->length = sourceLen; - } - return *this; -} - - -Zstring& Zstring::assign(const DefaultChar* source, size_t len) -{ - if (descr->refCount > 1 || descr->capacity < len) //allocate new string - *this = Zstring(source, len); - else - { - //overwrite this string - ::memcpy(data(), source, len * sizeof(DefaultChar)); //don't know if source is null-terminated - data()[len] = 0; //include null-termination - descr->length = len; - } - return *this; -} - - -Zstring& Zstring::operator+=(const Zstring& other) -{ - const size_t otherLen = other.length(); - if (otherLen != 0) - { - const size_t thisLen = length(); - const size_t newLen = thisLen + otherLen; - reserve(newLen); //make unshared and check capacity - - ::memcpy(data() + thisLen, other.c_str(), (otherLen + 1) * sizeof(DefaultChar)); //include null-termination - descr->length = newLen; - } - return *this; -} - - -Zstring& Zstring::operator+=(const DefaultChar* other) -{ - const size_t otherLen = defaultLength(other); - if (otherLen != 0) - { - const size_t thisLen = length(); - const size_t newLen = thisLen + otherLen; - reserve(newLen); //make unshared and check capacity - - ::memcpy(data() + thisLen, other, (otherLen + 1) * sizeof(DefaultChar)); //include NULL-termination - descr->length = newLen; - } - return *this; -} - - -Zstring& Zstring::operator+=(DefaultChar ch) -{ - const size_t oldLen = length(); - reserve(oldLen + 1); //make unshared and check capacity - data()[oldLen] = ch; - data()[oldLen + 1] = 0; - ++descr->length; - return *this; -} - - -void Zstring::reserve(size_t capacityNeeded) //make unshared and check capacity -{ - assert(capacityNeeded != 0); - - if (descr->refCount > 1) - { - //allocate a new string - const size_t oldLength = length(); - - StringDescriptor* newDescr = allocate(std::max(capacityNeeded, oldLength)); //reserve() must NEVER shrink the string - newDescr->length = oldLength; - - ::memcpy(reinterpret_cast<DefaultChar*>(newDescr + 1), c_str(), (oldLength + 1) * sizeof(DefaultChar)); //include NULL-termination - - decRef(); - descr = newDescr; - } - else if (descr->capacity < capacityNeeded) - { - //try to resize the current string (allocate anew if necessary) - const size_t newCapacity = getCapacityToAllocate(capacityNeeded); - -#ifndef NDEBUG - AllocationCount::getInstance().dec(c_str()); //test Zstring for memory leaks -#endif - - descr = static_cast<StringDescriptor*>(::realloc(descr, sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar))); - if (descr == NULL) - throw std::bad_alloc(); - -#ifndef NDEBUG - AllocationCount::getInstance().inc(c_str()); //test Zstring for memory leaks -#endif - - descr->capacity = newCapacity; - } -} - +/* +#include <fstream> + extern std::wofstream statShared; +extern std::wofstream statLowCapacity; +extern std::wofstream statOverwrite; + +std::wstring p(ptr); +p.erase(std::remove(p.begin(), p.end(), L'\n'), p.end()); +p.erase(std::remove(p.begin(), p.end(), L','), p.end()); + + if (descr(ptr)->refCount > 1) + statShared << + minCapacity << L"," << + descr(ptr)->refCount << L"," << + descr(ptr)->length << L"," << + descr(ptr)->capacity << L"," << + p << L"\n"; +else if (minCapacity > descr(ptr)->capacity) + statLowCapacity << + minCapacity << L"," << + descr(ptr)->refCount << L"," << + descr(ptr)->length << L"," << + descr(ptr)->capacity << L"," << + p << L"\n"; +else + statOverwrite << + minCapacity << L"," << + descr(ptr)->refCount << L"," << + descr(ptr)->length << L"," << + descr(ptr)->capacity << L"," << + p << L"\n"; +*/ + +#endif //FFS_WIN diff --git a/shared/zstring.h b/shared/zstring.h index 7b993fd0..a015dbe4 100644 --- a/shared/zstring.h +++ b/shared/zstring.h @@ -7,797 +7,206 @@ #ifndef ZSTRING_H_INCLUDED #define ZSTRING_H_INCLUDED -#include <cstring> //size_t, memcpy(), memcmp() -#include <cstdlib> //malloc(), free() -#include <cassert> -#include <vector> -#include <sstream> -#include <algorithm> //specialize std::swap -#include <functional> +#include "zbase.h" +#include <cstring> //strcmp() #ifndef NDEBUG -#include <set> +#include <map> #include <wx/thread.h> #endif -#ifdef ZSTRING_CHAR -typedef char DefaultChar; //use char strings -#define DefaultStr(x) x // -#elif defined ZSTRING_WIDE_CHAR -typedef wchar_t DefaultChar; //use wide character strings -#define DefaultStr(x) L ## x // -#endif - - -class Zstring -{ -public: - Zstring(); - Zstring(const DefaultChar* source); //string is copied: O(length) - Zstring(const DefaultChar* source, size_t length); //string is copied: O(length) - Zstring(const Zstring& source); //reference-counting => O(1) - ~Zstring(); - - operator const DefaultChar*() const; //implicit conversion to C string - - //wxWidgets-like functions - bool StartsWith(const DefaultChar* begin) const; - bool StartsWith(DefaultChar begin) const; - bool StartsWith(const Zstring& begin) const; - bool EndsWith(const DefaultChar* end) const; - bool EndsWith(const DefaultChar end) const; - bool EndsWith(const Zstring& end) const; - Zstring& Truncate(size_t newLen); - Zstring& Replace(const DefaultChar* old, const DefaultChar* replacement, bool replaceAll = true); - Zstring AfterLast( DefaultChar ch) const; //returns the whole string if ch not found - Zstring BeforeLast( DefaultChar ch) const; //returns empty string if ch not found - Zstring AfterFirst( DefaultChar ch) const; //returns empty string if ch not found - Zstring BeforeFirst(DefaultChar ch) const; //returns the whole string if ch not found - size_t Find(DefaultChar ch, bool fromEnd = false) const; //returns npos if not found - bool Matches(const DefaultChar* mask) const; - static bool Matches(const DefaultChar* name, const DefaultChar* mask); - Zstring& Trim(bool fromRight); //from right or left - std::vector<Zstring> Tokenize(const DefaultChar delimiter) const; -#ifdef FFS_WIN - Zstring& MakeUpper(); -#endif - - //std::string functions - size_t length() const; - const DefaultChar* c_str() const; - Zstring substr(size_t pos = 0, size_t len = npos) const; //allocate new string - bool empty() const; - void clear(); - int compare(size_t pos1, size_t n1, const DefaultChar* other) const; - size_t find(const DefaultChar* str, size_t pos = 0 ) const; - size_t find(DefaultChar ch, size_t pos = 0) const; - size_t rfind(DefaultChar ch, size_t pos = npos) const; - Zstring& replace(size_t pos1, size_t n1, const DefaultChar* str, size_t n2); - size_t size() const; - void reserve(size_t minCapacity); - Zstring& assign(const DefaultChar* source, size_t len); - void resize(size_t newSize, DefaultChar fillChar = 0 ); - - Zstring& operator=(const Zstring& source); - Zstring& operator=(const DefaultChar* source); - - - friend bool operator==(const Zstring& lhs, const Zstring& rhs); - friend bool operator==(const Zstring& lhs, const DefaultChar* rhs); - friend bool operator==(const DefaultChar* lhs, const Zstring& rhs); - - friend bool operator< (const Zstring& lhs, const Zstring& rhs); - friend bool operator< (const Zstring& lhs, const DefaultChar* rhs); - friend bool operator< (const DefaultChar* lhs, const Zstring& rhs); - - friend bool operator!=(const Zstring& lhs, const Zstring& rhs); - friend bool operator!=(const Zstring& lhs, const DefaultChar* rhs); - friend bool operator!=(const DefaultChar* lhs, const Zstring& rhs); - - void swap(Zstring& other); - - const DefaultChar operator[](size_t pos) const; - - Zstring& operator+=(const Zstring& other); - Zstring& operator+=(const DefaultChar* other); - Zstring& operator+=(DefaultChar ch); - - static const size_t npos = static_cast<size_t>(-1); - -private: - Zstring(int); //detect usage errors - - DefaultChar* data(); - - void initAndCopy(const DefaultChar* source, size_t length); - void incRef() const; //support for reference-counting - void decRef(); // - - //helper methods - static size_t defaultLength (const DefaultChar* input); //strlen() - static int defaultCompare(const DefaultChar* str1, const DefaultChar* str2); //strcmp() - static int defaultCompare(const DefaultChar* str1, const DefaultChar* str2, size_t count); //strncmp() - static const DefaultChar* defaultStrFind(const DefaultChar* str1, DefaultChar ch); //strchr() - static const DefaultChar* defaultStrFind(const DefaultChar* str1, const DefaultChar* str1End, const DefaultChar* str2); //"analog" to strstr() - static bool matchesHelper(const DefaultChar* string, const DefaultChar* mask); - - struct StringDescriptor - { - mutable unsigned int refCount; - size_t length; - size_t capacity; //allocated length without null-termination - }; - static StringDescriptor* allocate(const size_t newLength); - - StringDescriptor* descr; -}; - - -const Zstring operator+(const Zstring& lhs, const Zstring& rhs); -const Zstring operator+(const Zstring& lhs, const DefaultChar* rhs); -const Zstring operator+(const DefaultChar* lhs, const Zstring& rhs); -const Zstring operator+(DefaultChar lhs, const Zstring& rhs); -const Zstring operator+(const Zstring& lhs, DefaultChar rhs); - -template <class T> -Zstring numberToZstring(const T& number); //convert number to Zstring - -//Compare filenames: Windows does NOT distinguish between upper/lower-case, while Linux DOES -int cmpFileName(const Zstring& lhs, const Zstring& rhs); -int cmpFileName(const Zstring& lhs, const DefaultChar* rhs); -int cmpFileName(const DefaultChar* lhs, const Zstring& rhs); -int cmpFileName(const DefaultChar* lhs, const DefaultChar* rhs); - -struct LessFilename : public std::binary_function<Zstring, Zstring, bool>//case-insensitive on Windows, case-sensitive on Linux -{ - bool operator()(const Zstring& a, const Zstring& b) const; -}; - -namespace std -{ -template<> -inline -void swap(Zstring& rhs, Zstring& lhs) -{ - rhs.swap(lhs); -} -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//####################################################################################### -//begin of implementation - -//-------------standard helper functions --------------------------------------------------------------- -inline -size_t Zstring::defaultLength(const DefaultChar* input) //strlen() -{ - const DefaultChar* const startPos = input; - while (*input != 0) - ++input; - - return input - startPos; -} - - -inline -int Zstring::defaultCompare(const DefaultChar* str1, const DefaultChar* str2) //strcmp() -{ - while (*str1 == *str2) - { - if (*str1 == 0) - return 0; - ++str1; - ++str2; - } - - return *str1 - *str2; -} - - -inline -int Zstring::defaultCompare(const DefaultChar* str1, const DefaultChar* str2, size_t count) //strncmp() -{ - while (count-- != 0) - { - if (*str1 != *str2) - return *str1 - *str2; - - if (*str1 == 0) - return 0; - ++str1; - ++str2; - } - - return 0; -} - - -inline -const DefaultChar* Zstring::defaultStrFind(const DefaultChar* str1, DefaultChar ch) //strchr() -{ - while (*str1 != ch) //ch is allowed to be 0 by contract! must return end of string in this case - { - if (*str1 == 0) - return NULL; - - ++str1; - } - - return str1; -} - - -inline -const DefaultChar* Zstring::defaultStrFind(const DefaultChar* str1, const DefaultChar* str1End, const DefaultChar* str2) //"analog" to strstr() -{ - const size_t str2Len = defaultLength(str2); - - str1End -= str2Len; //no need to process the "last chunk" of str1 - ++str1End; // - - while(str1 < str1End) //don't use !=; str1End may be smaller than str1! - { - if(::memcmp(str1, str2, str2Len * sizeof(DefaultChar)) == 0) - return str1; - ++str1; - } - return NULL; -} -//-------------------------------------------------------------------------------------------------- - #ifndef NDEBUG -class AllocationCount //small test for memory leaks in Zstring +class LeakChecker //small test for memory leaks { public: - void inc(const DefaultChar* object) + void insert(const void* ptr, size_t size) { wxCriticalSectionLocker dummy(lockActStrings); - activeStrings.insert(object); + if (activeStrings.find(ptr) != activeStrings.end()) + reportProblem(std::string("Fatal Error: New memory points into occupied space: ") + rawMemToString(ptr, size)); + + activeStrings[ptr] = size; } - void dec(const DefaultChar* object) + void remove(const void* ptr) { wxCriticalSectionLocker dummy(lockActStrings); - activeStrings.erase(object); + + if (activeStrings.find(ptr) == activeStrings.end()) + reportProblem(std::string("Fatal Error: No memory available for deallocation at this location!")); + + activeStrings.erase(ptr); } - static AllocationCount& getInstance(); + static LeakChecker& instance(); private: - AllocationCount() {} - AllocationCount(const AllocationCount&); - ~AllocationCount(); + LeakChecker() {} + LeakChecker(const LeakChecker&); + LeakChecker& operator=(const LeakChecker&); + ~LeakChecker(); + + static std::string rawMemToString(const void* ptr, size_t size); + void reportProblem(const std::string& message); //throw (std::logic_error) wxCriticalSection lockActStrings; - std::set<const DefaultChar*> activeStrings; + typedef std::map<const void*, size_t> VoidPtrSizeMap; + VoidPtrSizeMap activeStrings; }; #endif //NDEBUG -inline -size_t getCapacityToAllocate(const size_t length) -{ - return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation -} - - -inline -Zstring::StringDescriptor* Zstring::allocate(const size_t newLength) +class AllocatorFreeStoreChecked { - //allocate and set data for new string - const size_t newCapacity = getCapacityToAllocate(newLength); - assert(newCapacity); - - StringDescriptor* const newDescr = static_cast<StringDescriptor*>(::malloc(sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar))); //use C-memory functions because of realloc() - if (newDescr == NULL) - throw std::bad_alloc(); - - newDescr->refCount = 1; - newDescr->length = newLength; - newDescr->capacity = newCapacity; - -#ifndef NDEBUG - AllocationCount::getInstance().inc(reinterpret_cast<DefaultChar*>(newDescr + 1)); //test Zstring for memory leaks -#endif - return newDescr; -} - - -inline -Zstring::Zstring() -{ - //static (dummy) empty Zstring -#ifdef ZSTRING_CHAR - static Zstring emptyString(""); -#elif defined ZSTRING_WIDE_CHAR - static Zstring emptyString(L""); -#endif - - emptyString.incRef(); - descr = emptyString.descr; -} - - -inline - -Zstring::Zstring(const DefaultChar* source) -{ - initAndCopy(source, defaultLength(source)); -} - - -inline -Zstring::Zstring(const DefaultChar* source, size_t sourceLen) -{ - initAndCopy(source, sourceLen); -} - - -inline -Zstring::Zstring(const Zstring& source) -{ - descr = source.descr; - incRef(); //reference counting! -} - - -inline -Zstring::~Zstring() -{ - decRef(); -} - - -inline -void Zstring::initAndCopy(const DefaultChar* source, size_t sourceLen) -{ - assert(source); - descr = allocate(sourceLen); - ::memcpy(data(), source, sourceLen * sizeof(DefaultChar)); - data()[sourceLen] = 0; -} - - -inline -void Zstring::incRef() const -{ - assert(descr); - ++descr->refCount; -} - - -inline -void Zstring::decRef() -{ - assert(descr && descr->refCount >= 1); //descr points to the begin of the allocated memory block - if (--descr->refCount == 0) +public: + static void* allocate(size_t size) //throw (std::bad_alloc) { #ifndef NDEBUG - AllocationCount::getInstance().dec(c_str()); //test Zstring for memory leaks + void* newMem = ::operator new(size); + LeakChecker::instance().insert(newMem, size); //test Zbase for memory leaks + return newMem; +#else + return ::operator new(size); #endif - ::free(descr); //beginning of whole memory block } -} - -inline -Zstring::operator const DefaultChar*() const -{ - return c_str(); -} - - -inline -Zstring& Zstring::operator=(const Zstring& source) -{ - Zstring(source).swap(*this); - return *this; -} - - -inline -size_t Zstring::Find(DefaultChar ch, bool fromEnd) const -{ - return fromEnd ? - rfind(ch, npos) : - find(ch, 0); -} - - -// get all characters after the last occurence of ch -// (returns the whole string if ch not found) -inline -Zstring Zstring::AfterLast(DefaultChar ch) const -{ - const size_t pos = rfind(ch, npos); - if (pos != npos ) - return Zstring(c_str() + pos + 1, length() - pos - 1); - else - return *this; -} - - -// get all characters before the last occurence of ch -// (returns empty string if ch not found) -inline -Zstring Zstring::BeforeLast(DefaultChar ch) const -{ - const size_t pos = rfind(ch, npos); - if (pos != npos) - return Zstring(c_str(), pos); //data is non-empty string in this context: else ch would not have been found! - else - return Zstring(); -} - - -//returns empty string if ch not found -inline -Zstring Zstring::AfterFirst(DefaultChar ch) const -{ - const size_t pos = find(ch, 0); - if (pos != npos) - return Zstring(c_str() + pos + 1, length() - pos - 1); - else - return Zstring(); - -} - -//returns the whole string if ch not found -inline -Zstring Zstring::BeforeFirst(DefaultChar ch) const -{ - const size_t pos = find(ch, 0); - if (pos != npos) - return Zstring(c_str(), pos); //data is non-empty string in this context: else ch would not have been found! - else - return *this; -} - - -inline -bool Zstring::StartsWith(const DefaultChar* begin) const -{ - const size_t beginLength = defaultLength(begin); - if (length() < beginLength) - return false; - return compare(0, beginLength, begin) == 0; -} - - -inline -bool Zstring::StartsWith(DefaultChar begin) const -{ - const size_t len = length(); - return len && (this->operator[](0) == begin); -} - - -inline -bool Zstring::StartsWith(const Zstring& begin) const -{ - const size_t beginLength = begin.length(); - if (length() < beginLength) - return false; - return compare(0, beginLength, begin.c_str()) == 0; -} - - -inline -bool Zstring::EndsWith(const DefaultChar* end) const -{ - const size_t thisLength = length(); - const size_t endLength = defaultLength(end); - if (thisLength < endLength) - return false; - return compare(thisLength - endLength, endLength, end) == 0; -} - - -inline -bool Zstring::EndsWith(const DefaultChar end) const -{ - const size_t len = length(); - return len && (this->operator[](len - 1) == end); -} - - -inline -bool Zstring::EndsWith(const Zstring& end) const -{ - const size_t thisLength = length(); - const size_t endLength = end.length(); - if (thisLength < endLength) - return false; - return compare(thisLength - endLength, endLength, end.c_str()) == 0; -} - - -inline -Zstring& Zstring::Truncate(size_t newLen) -{ - if (newLen < length()) + static void deallocate(void* ptr) { - if (descr->refCount > 1) //allocate new string - return *this = Zstring(c_str(), newLen); - else //overwrite this string - { - descr->length = newLen; - data()[newLen] = 0; - } +#ifndef NDEBUG + LeakChecker::instance().remove(ptr); //check for memory leaks +#endif + ::operator delete(ptr); } +}; - return *this; -} - - -inline -size_t Zstring::find(const DefaultChar* str, size_t pos) const -{ - assert(pos <= length()); - const DefaultChar* const found = defaultStrFind(c_str() + pos, c_str() + length(), str); - return found == NULL ? npos : found - c_str(); -} - - -inline -size_t Zstring::find(DefaultChar ch, size_t pos) const -{ - assert(pos <= length()); - const DefaultChar* thisStr = c_str(); - const DefaultChar* found = defaultStrFind(thisStr + pos, ch); - return found == NULL ? npos : found - thisStr; -} - - -inline -bool operator==(const Zstring& lhs, const Zstring& rhs) -{ - return lhs.length() != rhs.length() ? false : Zstring::defaultCompare(lhs.c_str(), rhs.c_str()) == 0; //memcmp() offers no better performance here... -} - - -inline -bool operator==(const Zstring& lhs, const DefaultChar* rhs) -{ - return Zstring::defaultCompare(lhs.c_str(), rhs) == 0; //overload using strcmp(char*, char*) should be fastest! -} +//############################## helper functions ############################################# +#if defined(FFS_WIN) || defined(FFS_LINUX) +//Compare filenames: Windows does NOT distinguish between upper/lower-case, while Linux DOES +template <class T, template <class, class> class SP, class AP> int cmpFileName(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs); -inline -bool operator==(const DefaultChar* lhs, const Zstring& rhs) +struct LessFilename //case-insensitive on Windows, case-sensitive on Linux { - return operator==(rhs, lhs); -} - + template <class T, template <class, class> class SP, class AP> + bool operator()(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) const; +}; -inline -bool operator<(const Zstring& lhs, const Zstring& rhs) +struct EqualFilename //case-insensitive on Windows, case-sensitive on Linux { - return Zstring::defaultCompare(lhs.c_str(), rhs.c_str()) < 0; -} + template <class T, template <class, class> class SP, class AP> + bool operator()(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) const; +}; +#endif +#ifdef FFS_WIN +template <template <class, class> class SP, class AP> +void MakeUpper(Zbase<wchar_t, SP, AP>& str); +#endif -inline -bool operator<(const Zstring& lhs, const DefaultChar* rhs) -{ - return Zstring::defaultCompare(lhs.c_str(), rhs) < 0; -} +#ifdef FFS_WIN //Windows stores filenames in wide character format +typedef wchar_t Zchar; +#define Zstr(x) L ## x -inline -bool operator<(const DefaultChar* lhs, const Zstring& rhs) -{ - return Zstring::defaultCompare(lhs, rhs.c_str()) < 0; -} +#elif defined FFS_LINUX //Linux uses UTF-8 +typedef char Zchar; +#define Zstr(x) x +#endif +//"The reason for all the fuss above" (Loki/SmartPtr) +typedef Zbase<Zchar, StorageRefCount, AllocatorFreeStoreChecked> Zstring; -inline -bool operator!=(const Zstring& lhs, const Zstring& rhs) -{ - return !operator==(lhs, rhs); -} -inline -bool operator!=(const Zstring& lhs, const DefaultChar* rhs) -{ - return !operator==(lhs, rhs); -} -inline -bool operator!=(const DefaultChar* lhs, const Zstring& rhs) -{ - return !operator==(lhs, rhs); -} -inline -int Zstring::compare(size_t pos1, size_t n1, const DefaultChar* other) const -{ - assert(n1 <= length() - pos1); - return defaultCompare(c_str() + pos1, other, n1); -} -inline -size_t Zstring::length() const -{ - return descr->length; -} -inline -size_t Zstring::size() const -{ - return descr->length; -} -inline -const DefaultChar* Zstring::c_str() const -{ - return reinterpret_cast<DefaultChar*>(descr + 1); -} -inline -DefaultChar* Zstring::data() -{ - return reinterpret_cast<DefaultChar*>(descr + 1); -} -inline -bool Zstring::empty() const -{ - return descr->length == 0; -} -inline -void Zstring::clear() -{ - *this = Zstring(); -} -inline -const DefaultChar Zstring::operator[](const size_t pos) const -{ - assert(pos < length()); - return c_str()[pos]; -} -inline -const Zstring operator+(const Zstring& lhs, const Zstring& rhs) -{ - return Zstring(lhs) += rhs; -} -inline -const Zstring operator+(const Zstring& lhs, const DefaultChar* rhs) -{ - return Zstring(lhs) += rhs; -} -inline -const Zstring operator+(const DefaultChar* lhs, const Zstring& rhs) +//################################# inline implementation ######################################## +#if defined(FFS_WIN) || defined(FFS_LINUX) +namespace z_impl { - return Zstring(lhs) += rhs; +int compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB); +void makeUpperCaseWin(wchar_t* str, size_t size); } +template <class T, template <class, class> class SP, class AP> inline -const Zstring operator+(DefaultChar lhs, const Zstring& rhs) +int cmpFileName(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) { - return (Zstring() += lhs) += rhs; +#ifdef FFS_WIN + return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length()); +#elif defined FFS_LINUX + return ::strcmp(lhs.c_str(), rhs.c_str()); //POSIX filenames don't have embedded 0 +#endif } +template <class T, template <class, class> class SP, class AP> inline -const Zstring operator+(const Zstring& lhs, DefaultChar rhs) +bool LessFilename::operator()(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) const { - return Zstring(lhs) += rhs; +#ifdef FFS_WIN + return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length()) < 0; +#elif defined FFS_LINUX + return ::strcmp(lhs.c_str(), rhs.c_str()) < 0; //POSIX filenames don't have embedded 0 +#endif } +template <class T, template <class, class> class SP, class AP> inline -void Zstring::resize(size_t newSize, DefaultChar fillChar) +bool EqualFilename::operator()(const Zbase<T, SP, AP>& lhs, const Zbase<T, SP, AP>& rhs) const { - const size_t oldSize = length(); - if (oldSize < newSize) - { - reserve(newSize); //make unshared and ensure capacity - - //fill up... - DefaultChar* strPtr = data() + oldSize; - const DefaultChar* const strEnd = data() + newSize; - while (strPtr != strEnd) - { - *strPtr = fillChar; - ++strPtr; - } - - data()[newSize] = 0; - descr->length = newSize; - } - else if (oldSize > newSize) - { - if (descr->refCount > 1) - *this = Zstring(c_str(), newSize); //no need to reserve() and copy the old string completely! - else //overwrite this string - { - data()[newSize] = 0; - descr->length = newSize; - } - } +#ifdef FFS_WIN + return z_impl::compareFilenamesWin(lhs.data(), rhs.data(), lhs.length(), rhs.length()) == 0; +#elif defined FFS_LINUX + return ::strcmp(lhs.c_str(), rhs.c_str()) == 0; //POSIX filenames don't have embedded 0 +#endif } +#endif //defined(FFS_WIN) || defined(FFS_LINUX) +#ifdef FFS_WIN +template <template <class, class> class SP, class AP> inline -void Zstring::swap(Zstring& other) +void MakeUpper(Zbase<wchar_t, SP, AP>& str) { - std::swap(descr, other.descr); + z_impl::makeUpperCaseWin(str.begin(), str.length()); } +#endif -template <class T> -inline -Zstring numberToZstring(const T& number) //convert number to string the C++ way +namespace std { - std::basic_ostringstream<DefaultChar> ss; - ss << number; - return Zstring(ss.str().c_str()); -} - - +template<> inline -int cmpFileName(const DefaultChar* lhs, const Zstring& rhs) +void swap(Zstring& rhs, Zstring& lhs) { - return cmpFileName(rhs, lhs); + rhs.swap(lhs); } - - -inline -bool LessFilename::operator()(const Zstring& a, const Zstring& b) const -{ -// //quick check based on string length -// const size_t aLength = a.data.shortName.length(); -// const size_t bLength = b.data.shortName.length(); -// if (aLength != bLength) -// return aLength < bLength; - return cmpFileName(a, b) < 0; } -#endif // ZSTRING_H_INCLUDED +#endif //ZSTRING_H_INCLUDED diff --git a/structures.cpp b/structures.cpp index 7515a0cc..ce41e93f 100644 --- a/structures.cpp +++ b/structures.cpp @@ -292,9 +292,9 @@ ffs3::MainConfiguration ffs3::merge(const std::vector<MainConfiguration>& mainCf if (fp->localFilter.includeFilter == FilterConfig().includeFilter) fp->localFilter.includeFilter = i->globalFilter.includeFilter; - fp->localFilter.excludeFilter.Trim(false); - fp->localFilter.excludeFilter = i->globalFilter.excludeFilter + DefaultStr("\n") + fp->localFilter.excludeFilter; - fp->localFilter.excludeFilter.Trim(false); + fp->localFilter.excludeFilter.Trim(true, false); + fp->localFilter.excludeFilter = i->globalFilter.excludeFilter + Zstr("\n") + fp->localFilter.excludeFilter; + fp->localFilter.excludeFilter.Trim(true, false); } fpMerged.insert(fpMerged.end(), fpTmp.begin(), fpTmp.end()); diff --git a/structures.h b/structures.h index 459cdf1b..ca6f8e7d 100644 --- a/structures.h +++ b/structures.h @@ -214,7 +214,7 @@ struct FilterConfig excludeFilter(exclude) {} FilterConfig() : //construct with default values - includeFilter(DefaultStr("*")) {} + includeFilter(Zstr("*")) {} Zstring includeFilter; Zstring excludeFilter; @@ -273,7 +273,7 @@ struct MainConfiguration MainConfiguration() : compareVar(CMP_BY_TIME_SIZE), handleSymlinks(SYMLINK_IGNORE), - globalFilter(DefaultStr("*"), standardExcludeFilter()), + globalFilter(Zstr("*"), standardExcludeFilter()), handleDeletion(MOVE_TO_RECYCLE_BIN) {} FolderPairEnh firstPair; //there needs to be at least one pair! diff --git a/synchronization.cpp b/synchronization.cpp index a571d29d..a64952b3 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -25,6 +25,7 @@ #ifdef FFS_WIN #include "shared/long_path_prefix.h" #include <boost/scoped_ptr.hpp> +#include "shared/perf.h" #endif using namespace ffs3; @@ -502,7 +503,7 @@ Zstring getSessionDeletionDir(const Zstring& deletionDirectory, const Zstring& p //ensure uniqueness for (int i = 1; ffs3::somethingExists(output); ++i) - output = formattedDir + DefaultChar('_') + numberToZstring(i); + output = formattedDir + Zchar('_') + Zstring::fromNumber(i); output += common::FILE_NAME_SEPARATOR; return output; @@ -524,12 +525,14 @@ SyncProcess::SyncProcess(xmlAccess::OptionalDialogs& warnings, namespace { -void ensureExists(const Zstring& dirname, const Zstring& templateDir = Zstring(), bool copyFilePermissions = false) //throw (FileError) +void ensureExists(const Zstring& dirname, const Zstring& templateDir, bool copyFilePermissions) //throw (FileError) { if (!dirname.empty()) //kind of pathological ? if (!ffs3::dirExists(dirname)) + { //lazy creation of alternate deletion directory (including super-directories of targetFile) ffs3::createDirectory(dirname, templateDir, false, copyFilePermissions); + } /*symbolic link handling: if "not traversing symlinks": fullName == c:\syncdir<symlinks>\some\dirs\leaf<symlink> => setting irrelevant @@ -593,24 +596,24 @@ DeletionHandling::DeletionHandling(const DeletionPolicy handleDel, switch (handleDel) { case DELETE_PERMANENTLY: - txtRemovingFile = wxToZ(_("Deleting file %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false); - txtRemovingSymlink = wxToZ(_("Deleting Symbolic Link %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false); - txtRemovingDirectory = wxToZ(_("Deleting folder %x")).Replace( DefaultStr("%x"), DefaultStr("\n\"%x\""), false); + txtRemovingFile = wxToZ(_("Deleting file %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false); + txtRemovingSymlink = wxToZ(_("Deleting Symbolic Link %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false); + txtRemovingDirectory = wxToZ(_("Deleting folder %x")).Replace( Zstr("%x"), Zstr("\n\"%x\""), false); break; case MOVE_TO_RECYCLE_BIN: - sessionDelDirLeft = getSessionDeletionDir(baseDirLeft, DefaultStr("FFS ")); - sessionDelDirRight = getSessionDeletionDir(baseDirRight, DefaultStr("FFS ")); + sessionDelDirLeft = getSessionDeletionDir(baseDirLeft, Zstr("FFS ")); + sessionDelDirRight = getSessionDeletionDir(baseDirRight, Zstr("FFS ")); - txtRemovingFile = txtRemovingSymlink = txtRemovingDirectory = wxToZ(_("Moving %x to Recycle Bin")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false); + txtRemovingFile = txtRemovingSymlink = txtRemovingDirectory = wxToZ(_("Moving %x to Recycle Bin")).Replace(Zstr("%x"), Zstr("\"%x\""), false); break; case MOVE_TO_CUSTOM_DIRECTORY: sessionDelDirLeft = sessionDelDirRight = getSessionDeletionDir(custDelFolder); - txtRemovingFile = wxToZ(_("Moving file %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false); - txtRemovingDirectory = wxToZ(_("Moving folder %x to user-defined directory %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false); - txtRemovingSymlink = wxToZ(_("Moving Symbolic Link %x to user-defined directory %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\"\n"), false).Replace(DefaultStr("%y"), Zstring(DefaultStr("\"")) + custDelFolder + DefaultStr("\""), false); + txtRemovingFile = wxToZ(_("Moving file %x to user-defined directory %y")). Replace(Zstr("%x"), Zstr("\"%x\"\n"), false).Replace(Zstr("%y"), Zstring(Zstr("\"")) + custDelFolder + Zstr("\""), false); + txtRemovingDirectory = wxToZ(_("Moving folder %x to user-defined directory %y")). Replace(Zstr("%x"), Zstr("\"%x\"\n"), false).Replace(Zstr("%y"), Zstring(Zstr("\"")) + custDelFolder + Zstr("\""), false); + txtRemovingSymlink = wxToZ(_("Moving Symbolic Link %x to user-defined directory %y")).Replace(Zstr("%x"), Zstr("\"%x\"\n"), false).Replace(Zstr("%y"), Zstring(Zstr("\"")) + custDelFolder + Zstr("\""), false); break; } } @@ -689,12 +692,14 @@ const Zstring& DeletionHandling::getSessionDir<RIGHT_SIDE>() const } +namespace +{ class MoveFileCallbackImpl : public MoveFileCallback //callback functionality { public: MoveFileCallbackImpl(StatusHandler& handler) : statusHandler_(handler) {} - virtual Response requestUiRefresh() //DON'T throw exceptions here, at least in Windows build! + virtual Response requestUiRefresh(const Zstring& currentObject) //DON'T throw exceptions here, at least in Windows build! { #ifdef FFS_WIN statusHandler_.requestUiRefresh(false); //don't allow throwing exception within this call: windows copying callback can't handle this @@ -711,47 +716,66 @@ private: }; +struct RemoveDirCallbackImpl : public RemoveDirCallback +{ + RemoveDirCallbackImpl(StatusHandler& handler) : statusHandler_(handler) {} + + virtual void requestUiRefresh(const Zstring& currentObject) + { + statusHandler_.requestUiRefresh(); //exceptions may be thrown here! + } + +private: + StatusHandler& statusHandler_; +}; +} + + template <ffs3::SelectedSide side> void DeletionHandling::removeFile(const FileSystemObject& fileObj) const { + using namespace ffs3; + switch (deletionType) { - case ffs3::DELETE_PERMANENTLY: + case DELETE_PERMANENTLY: ffs3::removeFile(fileObj.getFullName<side>()); break; - case ffs3::MOVE_TO_RECYCLE_BIN: - if (ffs3::fileExists(fileObj.getFullName<side>())) + case MOVE_TO_RECYCLE_BIN: + if (fileExists(fileObj.getFullName<side>())) { const Zstring targetFile = getSessionDir<side>() + fileObj.getRelativeName<side>(); //altDeletionDir ends with path separator const Zstring targetDir = targetFile.BeforeLast(common::FILE_NAME_SEPARATOR); - ensureExists(targetDir); //throw (FileError) + if (!dirExists(targetDir)) + createDirectory(targetDir); //throw (FileError) try //rename file: no copying!!! { //performance optimization!! Instead of moving each object into recycle bin separately, we rename them ony by one into a //temporary directory and delete this directory only ONCE! - ffs3::renameFile(fileObj.getFullName<side>(), targetFile); //throw (FileError); + renameFile(fileObj.getFullName<side>(), targetFile); //throw (FileError); } catch (...) { //if anything went wrong, move to recycle bin the standard way (single file processing: slow) - ffs3::moveToRecycleBin(fileObj.getFullName<side>()); //throw (FileError) + moveToRecycleBin(fileObj.getFullName<side>()); //throw (FileError) } } break; - case ffs3::MOVE_TO_CUSTOM_DIRECTORY: - if (ffs3::fileExists(fileObj.getFullName<side>())) + case MOVE_TO_CUSTOM_DIRECTORY: + if (fileExists(fileObj.getFullName<side>())) { const Zstring targetFile = getSessionDir<side>() + fileObj.getRelativeName<side>(); //altDeletionDir ends with path separator const Zstring targetDir = targetFile.BeforeLast(common::FILE_NAME_SEPARATOR); - ensureExists(targetDir); //throw (FileError) + if (!dirExists(targetDir)) + createDirectory(targetDir); //throw (FileError) MoveFileCallbackImpl callBack(statusUpdater_); //if file needs to be copied we need callback functionality to update screen and offer abort - ffs3::moveFile(fileObj.getFullName<side>(), targetFile, &callBack); + moveFile(fileObj.getFullName<side>(), targetFile, &callBack); } break; } @@ -761,45 +785,52 @@ void DeletionHandling::removeFile(const FileSystemObject& fileObj) const template <ffs3::SelectedSide side> void DeletionHandling::removeFolder(const FileSystemObject& dirObj) const { + using namespace ffs3; + switch (deletionType) { - case ffs3::DELETE_PERMANENTLY: - ffs3::removeDirectory(dirObj.getFullName<side>()); - break; + case DELETE_PERMANENTLY: + { + RemoveDirCallbackImpl remDirCallback(statusUpdater_); + removeDirectory(dirObj.getFullName<side>(), &remDirCallback); + } + break; - case ffs3::MOVE_TO_RECYCLE_BIN: - if (ffs3::dirExists(dirObj.getFullName<side>())) + case MOVE_TO_RECYCLE_BIN: + if (dirExists(dirObj.getFullName<side>())) { const Zstring targetDir = getSessionDir<side>() + dirObj.getRelativeName<side>(); const Zstring targetSuperDir = targetDir.BeforeLast(common::FILE_NAME_SEPARATOR); - ensureExists(targetSuperDir); //throw (FileError) + if (!dirExists(targetSuperDir)) + createDirectory(targetSuperDir); //throw (FileError) try //rename directory: no copying!!! { //performance optimization!! Instead of moving each object into recycle bin separately, we rename them ony by one into a //temporary directory and delete this directory only ONCE! - ffs3::renameFile(dirObj.getFullName<side>(), targetDir); //throw (FileError); + renameFile(dirObj.getFullName<side>(), targetDir); //throw (FileError); } catch (...) { //if anything went wrong, move to recycle bin the standard way (single file processing: slow) - ffs3::moveToRecycleBin(dirObj.getFullName<side>()); //throw (FileError) + moveToRecycleBin(dirObj.getFullName<side>()); //throw (FileError) } } break; - case ffs3::MOVE_TO_CUSTOM_DIRECTORY: - if (ffs3::dirExists(dirObj.getFullName<side>())) + case MOVE_TO_CUSTOM_DIRECTORY: + if (dirExists(dirObj.getFullName<side>())) { const Zstring targetDir = getSessionDir<side>() + dirObj.getRelativeName<side>(); const Zstring targetSuperDir = targetDir.BeforeLast(common::FILE_NAME_SEPARATOR); - ensureExists(targetSuperDir); //throw (FileError) + if (!dirExists(targetSuperDir)) + createDirectory(targetSuperDir); //throw (FileError) MoveFileCallbackImpl callBack(statusUpdater_); //if files need to be copied, we need callback functionality to update screen and offer abort - ffs3::moveDirectory(dirObj.getFullName<side>(), targetDir, true, &callBack); + moveDirectory(dirObj.getFullName<side>(), targetDir, true, &callBack); } break; } @@ -872,12 +903,12 @@ public: delHandling_(delHandling), verifyCopiedFiles_(syncProc.verifyCopiedFiles_), copyFilePermissions_(syncProc.copyFilePermissions_), - txtCopyingFile (wxToZ(_("Copying file %x to %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)), - txtCopyingLink (wxToZ(_("Copying Symbolic Link %x to %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)), - txtOverwritingFile(wxToZ(_("Copying file %x overwriting %y")). Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)), - txtOverwritingLink(wxToZ(_("Copying Symbolic Link %x overwriting %y")).Replace(DefaultStr("%x"), DefaultStr("\"%x\""), false).Replace(DefaultStr("%y"), DefaultStr("\n\"%y\""), false)), - txtCreatingFolder (wxToZ(_("Creating folder %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)), - txtVerifying (wxToZ(_("Verifying file %x")). Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false)) {} + txtCopyingFile (wxToZ(_("Copying new file %x to %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)), + txtCopyingLink (wxToZ(_("Copying new Symbolic Link %x to %y")).Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)), + txtOverwritingFile(wxToZ(_("Overwriting file %x in %y")). Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)), + txtOverwritingLink(wxToZ(_("Overwriting Symbolic Link %x in %y")).Replace(Zstr("%x"), Zstr("\"%x\""), false).Replace(Zstr("%y"), Zstr("\n\"%y\""), false)), + txtCreatingFolder (wxToZ(_("Creating folder %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""), false)), + txtVerifying (wxToZ(_("Verifying file %x")). Replace(Zstr("%x"), Zstr("\n\"%x\""), false)) {} template <bool reduceDiskSpace> //"true" if files deletion shall happen only @@ -986,9 +1017,9 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const target = fileObj.getBaseDirPf<LEFT_SIDE>() + fileObj.getRelativeName<RIGHT_SIDE>(); statusText = txtCopyingFile; - statusText.Replace(DefaultStr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false); + statusText.Replace(Zstr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh copyFileUpdating(fileObj.getFullName<RIGHT_SIDE>(), target, fileObj.getFileSize<RIGHT_SIDE>()); @@ -998,9 +1029,9 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const target = fileObj.getBaseDirPf<RIGHT_SIDE>() + fileObj.getRelativeName<LEFT_SIDE>(); statusText = txtCopyingFile; - statusText.Replace(DefaultStr("%x"), fileObj.getShortName<LEFT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getShortName<LEFT_SIDE>(), false); + statusText.Replace(Zstr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh copyFileUpdating(fileObj.getFullName<LEFT_SIDE>(), target, fileObj.getFileSize<LEFT_SIDE>()); @@ -1008,8 +1039,8 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const case SO_DELETE_LEFT: statusText = delHandling_.getTxtRemovingFile(); - statusText.Replace(DefaultStr("%x"), fileObj.getFullName<LEFT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getFullName<LEFT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFile<LEFT_SIDE>(fileObj); //throw FileError() @@ -1017,8 +1048,8 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const case SO_DELETE_RIGHT: statusText = delHandling_.getTxtRemovingFile(); - statusText.Replace(DefaultStr("%x"), fileObj.getFullName<RIGHT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getFullName<RIGHT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFile<RIGHT_SIDE>(fileObj); //throw FileError() @@ -1028,9 +1059,9 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const 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(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getShortName<LEFT_SIDE>(), false); + statusText.Replace(Zstr("%y"), fileObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFile<RIGHT_SIDE>(fileObj); //throw FileError() @@ -1043,9 +1074,9 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const 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(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), fileObj.getShortName<RIGHT_SIDE>(), false); + statusText.Replace(Zstr("%y"), fileObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFile<LEFT_SIDE>(fileObj); //throw FileError() @@ -1080,9 +1111,9 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>(); statusText = txtCopyingLink; - statusText.Replace(DefaultStr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false); + statusText.Replace(Zstr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh copySymlink(linkObj.getFullName<RIGHT_SIDE>(), target, linkObj.getLinkType<RIGHT_SIDE>()); @@ -1092,9 +1123,9 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>(); statusText = txtCopyingLink; - statusText.Replace(DefaultStr("%x"), linkObj.getShortName<LEFT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getShortName<LEFT_SIDE>(), false); + statusText.Replace(Zstr("%y"), target.BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh copySymlink(linkObj.getFullName<LEFT_SIDE>(), target, linkObj.getLinkType<LEFT_SIDE>()); @@ -1102,8 +1133,8 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const case SO_DELETE_LEFT: statusText = delHandling_.getTxtRemovingSymLink(); - statusText.Replace(DefaultStr("%x"), linkObj.getFullName<LEFT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getFullName<LEFT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError() @@ -1111,8 +1142,8 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const case SO_DELETE_RIGHT: statusText = delHandling_.getTxtRemovingSymLink(); - statusText.Replace(DefaultStr("%x"), linkObj.getFullName<RIGHT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getFullName<RIGHT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError() @@ -1122,9 +1153,9 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const target = linkObj.getBaseDirPf<RIGHT_SIDE>() + linkObj.getRelativeName<LEFT_SIDE>(); statusText = txtOverwritingLink; - statusText.Replace(DefaultStr("%x"), linkObj.getShortName<LEFT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), linkObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getShortName<LEFT_SIDE>(), false); + statusText.Replace(Zstr("%y"), linkObj.getFullName<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh deleteSymlink<RIGHT_SIDE>(linkObj); //throw FileError() @@ -1137,9 +1168,9 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const target = linkObj.getBaseDirPf<LEFT_SIDE>() + linkObj.getRelativeName<RIGHT_SIDE>(); statusText = txtOverwritingLink; - statusText.Replace(DefaultStr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false); - statusText.Replace(DefaultStr("%y"), linkObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), linkObj.getShortName<RIGHT_SIDE>(), false); + statusText.Replace(Zstr("%y"), linkObj.getFullName<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh deleteSymlink<LEFT_SIDE>(linkObj); //throw FileError() @@ -1175,8 +1206,8 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const target = dirObj.getBaseDirPf<LEFT_SIDE>() + dirObj.getRelativeName<RIGHT_SIDE>(); statusText = txtCreatingFolder; - statusText.Replace(DefaultStr("%x"), target, false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), target, false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh //some check to catch the error that directory on source has been deleted externally after "compare"... @@ -1189,8 +1220,8 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const target = dirObj.getBaseDirPf<RIGHT_SIDE>() + dirObj.getRelativeName<LEFT_SIDE>(); statusText = txtCreatingFolder; - statusText.Replace(DefaultStr("%x"), target, false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), target, false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh //some check to catch the error that directory on source has been deleted externally after "compare"... @@ -1202,8 +1233,8 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const case SO_DELETE_LEFT: //status information statusText = delHandling_.getTxtRemovingDir(); - statusText.Replace(DefaultStr("%x"), dirObj.getFullName<LEFT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), dirObj.getFullName<LEFT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFolder<LEFT_SIDE>(dirObj); //throw FileError() @@ -1221,8 +1252,8 @@ void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const case SO_DELETE_RIGHT: //status information statusText = delHandling_.getTxtRemovingDir(); - statusText.Replace(DefaultStr("%x"), dirObj.getFullName<RIGHT_SIDE>(), false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), dirObj.getFullName<RIGHT_SIDE>(), false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh delHandling_.removeFolder<RIGHT_SIDE>(dirObj); //throw FileError() @@ -1297,10 +1328,16 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf if (syncConfig.size() != folderCmp.size()) throw std::logic_error("Programming Error: Contract violation!"); + std::vector<std::pair<bool, bool> > baseDirNeeded; + for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) { - const SyncStatistics statisticsFolderPair(*j); const FolderPairSyncCfg& folderPairCfg = syncConfig[j - folderCmp.begin()]; + const SyncStatistics statisticsFolderPair(*j); + + //save information whether base directories need to be created (if not yet existing) + baseDirNeeded.push_back(std::make_pair(statisticsFolderPair.getCreate(true, false) > 0, + statisticsFolderPair.getCreate(false, true) > 0)); if (statisticsFolderPair.getOverwrite() + statisticsFolderPair.getDelete() > 0) { @@ -1409,9 +1446,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf { statusUpdater_.requestUiRefresh(); } - virtual void updateStatusText(const Zstring& text) + virtual void reportInfo(const Zstring& text) { - statusUpdater_.updateStatusText(text); + statusUpdater_.reportInfo(text); } private: StatusHandler& statusUpdater_; @@ -1430,7 +1467,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf const FolderPairSyncCfg& folderPairCfg = syncConfig[j - folderCmp.begin()]; //exclude some pathological case (leftdir, rightdir are empty) - if (j->getBaseDir<LEFT_SIDE>() == j->getBaseDir<RIGHT_SIDE>()) + if (EqualFilename()(j->getBaseDir<LEFT_SIDE>(), j->getBaseDir<RIGHT_SIDE>())) continue; //------------------------------------------------------------------------------------------ @@ -1441,7 +1478,22 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf 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)); + statusUpdater.reportInfo(wxToZ(statusTxt)); +//------------------------------------------------------------------------------------------ + //(try to) create base dir first -> no symlink or attribute copying! + if (baseDirNeeded[j - folderCmp.begin()].first) + try + { + ffs3::createDirectory(j->getBaseDir<LEFT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR)); + } + catch (...) {} + + if (baseDirNeeded[j - folderCmp.begin()].second) + try //create base dir first -> no symlink or attribute copying! + { + ffs3::createDirectory(j->getBaseDir<RIGHT_SIDE>().BeforeLast(common::FILE_NAME_SEPARATOR)); + } + catch (...) {} //------------------------------------------------------------------------------------------ //generate name of alternate deletion directory (unique for session AND folder pair) @@ -1485,7 +1537,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf //update synchronization database (automatic sync only) if (folderPairCfg.inAutomaticMode) { - statusUpdater.updateStatusText(wxToZ(_("Generating database..."))); + statusUpdater.reportInfo(wxToZ(_("Generating database..."))); statusUpdater.forceUiRefresh(); tryReportingError(statusUpdater, boost::bind(ffs3::saveToDisk, boost::cref(*j))); //these call may throw in error-callback! } @@ -1694,8 +1746,8 @@ private: void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring& target) const { Zstring statusText = txtVerifying; - statusText.Replace(DefaultStr("%x"), target, false); - statusUpdater_.updateStatusText(statusText); + statusText.Replace(Zstr("%x"), target, false); + statusUpdater_.reportInfo(statusText); statusUpdater_.requestUiRefresh(); //trigger display refresh VerifyStatusUpdater callback(statusUpdater_); diff --git a/ui/batch_config.cpp b/ui/batch_config.cpp index 21a2f2cd..5aca5d67 100644 --- a/ui/batch_config.cpp +++ b/ui/batch_config.cpp @@ -14,6 +14,7 @@ #include "msg_popup.h" #include <wx/dnd.h> #include <wx/msgdlg.h> +#include "mouse_move_dlg.h" using namespace ffs3; @@ -91,7 +92,7 @@ private: /|\ /|\ _________|______________ ________| | | | - FirstBatchFolderPairCfg BatchFolderPairPanel + DirectoryPairBatchFirst DirectoryPairBatch */ template <class GuiPanel> @@ -117,42 +118,72 @@ private: }; -class BatchFolderPairPanel : - public BatchFolderPairGenerated, //BatchFolderPairPanel "owns" BatchFolderPairGenerated! +class DirectoryPairBatch: + public BatchFolderPairGenerated, //DirectoryPairBatch "owns" BatchFolderPairGenerated! public FolderPairCallback<BatchFolderPairGenerated> { public: - BatchFolderPairPanel(wxWindow* parent, BatchDialog& batchDialog) : + DirectoryPairBatch(wxWindow* parent, BatchDialog& batchDialog) : BatchFolderPairGenerated(parent), FolderPairCallback<BatchFolderPairGenerated>(static_cast<BatchFolderPairGenerated&>(*this), batchDialog), //pass BatchFolderPairGenerated part... - dragDropOnLeft( m_panelLeft, m_dirPickerLeft, m_directoryLeft), - dragDropOnRight(m_panelRight, m_dirPickerRight, m_directoryRight) {} + dirNameLeft( m_panelLeft, m_dirPickerLeft, m_directoryLeft), + dirNameRight(m_panelRight, m_dirPickerRight, m_directoryRight) {} + + void setValues(const Zstring& leftDir, const Zstring& rightDir, AltSyncCfgPtr syncCfg, const FilterConfig& filter) + { + setConfig(syncCfg, filter); + dirNameLeft.setName(leftDir); + dirNameRight.setName(rightDir); + } + Zstring getLeftDir() const + { + return dirNameLeft.getName(); + } + Zstring getRightDir() const + { + return dirNameRight.getName(); + } private: //support for drag and drop - DragDropOnDlg dragDropOnLeft; - DragDropOnDlg dragDropOnRight; + DirectoryName dirNameLeft; + DirectoryName dirNameRight; }; -class FirstBatchFolderPairCfg : public FolderPairCallback<BatchDlgGenerated> +class DirectoryPairBatchFirst : public FolderPairCallback<BatchDlgGenerated> { public: - FirstBatchFolderPairCfg(BatchDialog& batchDialog) : + DirectoryPairBatchFirst(BatchDialog& batchDialog) : FolderPairCallback<BatchDlgGenerated>(batchDialog, batchDialog), //prepare drag & drop - dragDropOnLeft(batchDialog.m_panelLeft, + dirNameLeft(batchDialog.m_panelLeft, batchDialog.m_dirPickerLeft, batchDialog.m_directoryLeft), - dragDropOnRight(batchDialog.m_panelRight, + dirNameRight(batchDialog.m_panelRight, batchDialog.m_dirPickerRight, batchDialog.m_directoryRight) {} + void setValues(const Zstring& leftDir, const Zstring& rightDir, AltSyncCfgPtr syncCfg, const FilterConfig& filter) + { + setConfig(syncCfg, filter); + dirNameLeft.setName(leftDir); + dirNameRight.setName(rightDir); + } + Zstring getLeftDir() const + { + return dirNameLeft.getName(); + } + Zstring getRightDir() const + { + return dirNameRight.getName(); + } + private: //support for drag and drop - DragDropOnDlg dragDropOnLeft; - DragDropOnDlg dragDropOnRight; + DirectoryName dirNameLeft; + DirectoryName dirNameRight; }; @@ -178,6 +209,16 @@ BatchDialog::~BatchDialog() {} //non-inline destructor for std::auto_ptr to work void BatchDialog::init() { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, + m_panelOverview, + m_panelLogging, + m_staticText56, + m_staticText44, + m_bitmap27); //ownership passed to "this" +#endif + wxWindowUpdateLocker dummy(this); //avoid display distortion m_bpButtonCmpConfig->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("cmpConfig"))); @@ -186,13 +227,13 @@ void BatchDialog::init() m_bpButtonHelp->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("help"))); //init handling of first folder pair - firstFolderPair.reset(new FirstBatchFolderPairCfg(*this)); + firstFolderPair.reset(new DirectoryPairBatchFirst(*this)); m_bpButtonFilter->Connect(wxEVT_RIGHT_DOWN, wxCommandEventHandler(BatchDialog::OnGlobalFilterOpenContext), NULL, this); //prepare drag & drop for loading of *.ffs_batch files SetDropTarget(new BatchFileDropEvent(*this)); - dragDropOnLogfileDir.reset(new DragDropOnDlg(m_panelLogging, m_dirPickerLogfileDir, m_textCtrlLogfileDir)); + logfileDir.reset(new DirectoryName(m_panelLogging, m_dirPickerLogfileDir, m_textCtrlLogfileDir)); //set icons for this dialog m_bpButtonAddPair->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); @@ -469,7 +510,7 @@ void BatchDialog::OnLoadBatchJob(wxCommandEvent& event) inline -FolderPairEnh getEnahncedPair(const BatchFolderPairPanel* panel) +FolderPairEnh getEnahncedPair(const DirectoryPairBatch* panel) { return FolderPairEnh(panel->getLeftDir(), panel->getRightDir(), @@ -498,7 +539,7 @@ xmlAccess::XmlBatchConfig BatchDialog::getCurrentConfiguration() const //load structure with batch settings "batchCfg" batchCfg.silent = m_checkBoxSilent->GetValue(); - batchCfg.logFileDirectory = m_textCtrlLogfileDir->GetValue(); + batchCfg.logFileDirectory = zToWx(logfileDir->getName()); batchCfg.handleError = getSelectionHandleError(); return batchCfg; @@ -566,7 +607,7 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) localBatchCfg = batchCfg; m_checkBoxSilent->SetValue(batchCfg.silent); - m_textCtrlLogfileDir->SetValue(batchCfg.logFileDirectory); + logfileDir->setName(wxToZ(batchCfg.logFileDirectory)); //error handling is dependent from m_checkBoxSilent! /|\ \|/ setSelectionHandleError(batchCfg.handleError); @@ -614,7 +655,7 @@ void BatchDialog::OnRemoveFolderPair(wxCommandEvent& event) { //find folder pair originating the event const wxObject* const eventObj = event.GetEventObject(); - for (std::vector<BatchFolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<DirectoryPairBatch*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) { if (eventObj == static_cast<wxObject*>((*i)->m_bpButtonRemovePair)) { @@ -684,7 +725,7 @@ void BatchDialog::addFolderPair(const std::vector<ffs3::FolderPairEnh>& newPairs int pairHeight = 0; for (std::vector<ffs3::FolderPairEnh>::const_iterator i = newPairs.begin(); i != newPairs.end(); ++i) { - BatchFolderPairPanel* newPair = new BatchFolderPairPanel(m_scrolledWindow6, *this); + DirectoryPairBatch* newPair = new DirectoryPairBatch(m_scrolledWindow6, *this); if (addFront) { @@ -733,7 +774,7 @@ void BatchDialog::removeAddFolderPair(const int pos) if (0 <= pos && pos < static_cast<int>(additionalFolderPairs.size())) { //remove folder pairs from window - BatchFolderPairPanel* pairToDelete = additionalFolderPairs[pos]; + DirectoryPairBatch* pairToDelete = additionalFolderPairs[pos]; const int pairHeight = pairToDelete->GetSize().GetHeight(); bSizerAddFolderPairs->Detach(pairToDelete); //Remove() does not work on Window*, so do it manually diff --git a/ui/batch_config.h b/ui/batch_config.h index b2ff0cc8..62645c78 100644 --- a/ui/batch_config.h +++ b/ui/batch_config.h @@ -13,11 +13,11 @@ namespace ffs3 { -class DragDropOnDlg; +class DirectoryName; } -class BatchFolderPairPanel; -class FirstBatchFolderPairCfg; +class DirectoryPairBatch; +class DirectoryPairBatchFirst; class BatchDialog: public BatchDlgGenerated @@ -79,8 +79,8 @@ private: xmlAccess::XmlBatchConfig getCurrentConfiguration() const; - boost::shared_ptr<FirstBatchFolderPairCfg> firstFolderPair; //always bound!!! - std::vector<BatchFolderPairPanel*> additionalFolderPairs; + boost::shared_ptr<DirectoryPairBatchFirst> firstFolderPair; //always bound!!! + std::vector<DirectoryPairBatch*> additionalFolderPairs; //used when saving batch file wxString proposedBatchFileName; @@ -89,8 +89,7 @@ private: std::auto_ptr<wxMenu> contextMenu; - //add drag & drop support when selecting logfile directory - std::auto_ptr<ffs3::DragDropOnDlg> dragDropOnLogfileDir; + std::auto_ptr<ffs3::DirectoryName> logfileDir; }; #endif // BATCHCONFIG_H_INCLUDED diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp index e67e4426..c3dfc8df 100644 --- a/ui/batch_status_handler.cpp +++ b/ui/batch_status_handler.cpp @@ -33,7 +33,7 @@ public: //write header wxString headerLine = wxString(wxT("FreeFileSync - ")) + _("Batch execution") + wxT(" (") + - _("Date") + wxT(": ") + wxDateTime::Now().FormatDate() + wxT(" ") + //"Date" is used at other places too + _("Date") + wxT(": ") + wxDateTime::Now().FormatDate() + wxT(" ") + //"Date" is used at other places, too _("Time") + wxT(":") + wxT(" ") + wxDateTime::Now().FormatTime() + wxT(")"); logFile.Write(headerLine + wxChar('\n')); logFile.Write(wxString().Pad(headerLine.Len(), wxChar('-')) + wxChar('\n') + wxChar('\n')); @@ -213,7 +213,7 @@ BatchStatusHandler::~BatchStatusHandler() inline -void BatchStatusHandler::updateStatusText(const Zstring& text) +void BatchStatusHandler::reportInfo(const Zstring& text) { if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING && logFile.get()) //write file transfer information to log errorLog.logInfo(zToWx(text)); @@ -266,7 +266,7 @@ void BatchStatusHandler::updateProcessedData(int objectsProcessed, wxLongLong da } -void BatchStatusHandler::reportInfo(const wxString& infoMessage) +void BatchStatusHandler::logInfo(const wxString& infoMessage) { errorLog.logInfo(infoMessage); } diff --git a/ui/batch_status_handler.h b/ui/batch_status_handler.h index f5497b0f..bc4c5bde 100644 --- a/ui/batch_status_handler.h +++ b/ui/batch_status_handler.h @@ -28,12 +28,12 @@ public: int& returnVal); ~BatchStatusHandler(); - virtual void updateStatusText(const Zstring& text); virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void reportInfo(const Zstring& text); virtual void forceUiRefresh(); - void reportInfo(const wxString& infoMessage); + void logInfo(const wxString& infoMessage); virtual void reportWarning(const wxString& warningMessage, bool& warningActive); virtual ErrorHandler::Response reportError(const wxString& errorMessage); virtual void reportFatalError(const wxString& errorMessage); diff --git a/ui/folder_pair.h b/ui/folder_pair.h index 27f3ab29..5dc016ef 100644 --- a/ui/folder_pair.h +++ b/ui/folder_pair.h @@ -8,7 +8,7 @@ #define FOLDERPAIR_H_INCLUDED #include "../structures.h" -#include "../shared/drag_n_drop.h" +#include "../shared/dir_name.h" #include "../library/resources.h" #include "small_dlgs.h" #include "sync_cfg.h" @@ -27,17 +27,6 @@ class FolderPairPanelBasic : private wxEvtHandler public: typedef boost::shared_ptr<const ffs3::AlternateSyncConfig> AltSyncCfgPtr; - - Zstring getLeftDir() const - { - return wxToZ(basicPanel_.m_directoryLeft->GetValue()); - } - - Zstring getRightDir() const - { - return wxToZ(basicPanel_.m_directoryRight->GetValue()); - } - AltSyncCfgPtr getAltSyncConfig() const { return altSyncConfig; @@ -48,18 +37,10 @@ public: return localFilter; } - void setValues(const Zstring& leftDir, - const Zstring& rightDir, - AltSyncCfgPtr syncCfg, - const FilterConfig& filter) + void setConfig(AltSyncCfgPtr syncCfg, const FilterConfig& filter) { altSyncConfig = syncCfg; localFilter = filter; - - //insert directory names - ffs3::setDirectoryName(zToWx(leftDir), basicPanel_.m_directoryLeft, basicPanel_.m_dirPickerLeft); - ffs3::setDirectoryName(zToWx(rightDir), basicPanel_.m_directoryRight, basicPanel_.m_dirPickerRight); - refreshButtons(); } @@ -145,7 +126,7 @@ private: basicPanel_.PopupMenu(contextMenu.get()); //show context menu } - virtual MainConfiguration getMainConfig() const = 0; + virtual MainConfiguration getMainConfig() const = 0; virtual wxWindow* getParentWindow() = 0; virtual void OnAltSyncCfgChange() {}; diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp index 59257708..659a40f3 100644 --- a/ui/gui_generated.cpp +++ b/ui/gui_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 16 2008) +// C++ code generated with wxFormBuilder (version Sep 8 2010) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -26,12 +26,14 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuItem11 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("2. &Synchronize...") ) + wxT('\t') + wxT("ALT-S"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItem11 ); - m_menuFile->AppendSeparator(); + wxMenuItem* m_separator1; + m_separator1 = m_menuFile->AppendSeparator(); m_menuItemSwitchView = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("S&witch view") ) + wxT('\t') + wxT("ALT-W"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItemSwitchView ); - m_menuFile->AppendSeparator(); + wxMenuItem* m_separator2; + m_separator2 = m_menuFile->AppendSeparator(); m_menuItemNew = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("&New") ) + wxT('\t') + wxT("CTRL-N"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItemNew ); @@ -42,19 +44,21 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuItemLoad = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("&Load configuration...") ) + wxT('\t') + wxT("CTRL-L"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItemLoad ); - m_menuFile->AppendSeparator(); + wxMenuItem* m_separator3; + m_separator3 = m_menuFile->AppendSeparator(); wxMenuItem* m_menuItem4; m_menuItem4 = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("&Quit") ) + wxT('\t') + wxT("CTRL-Q"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItem4 ); - m_menubar1->Append( m_menuFile, _("&File") ); + m_menubar1->Append( m_menuFile, _("&File") ); m_menuAdvanced = new wxMenu(); m_menuLanguages = new wxMenu(); m_menuAdvanced->Append( -1, _("&Language"), m_menuLanguages ); - m_menuAdvanced->AppendSeparator(); + wxMenuItem* m_separator4; + m_separator4 = m_menuAdvanced->AppendSeparator(); m_menuItemGlobSett = new wxMenuItem( m_menuAdvanced, wxID_ANY, wxString( _("&Global settings...") ) , wxEmptyString, wxITEM_NORMAL ); m_menuAdvanced->Append( m_menuItemGlobSett ); @@ -66,7 +70,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuItem5 = new wxMenuItem( m_menuAdvanced, wxID_ANY, wxString( _("&Export file list...") ) , wxEmptyString, wxITEM_NORMAL ); m_menuAdvanced->Append( m_menuItem5 ); - m_menubar1->Append( m_menuAdvanced, _("&Advanced") ); + m_menubar1->Append( m_menuAdvanced, _("&Advanced") ); m_menuHelp = new wxMenu(); wxMenuItem* m_menuItemReadme; @@ -76,12 +80,13 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuItemCheckVer = new wxMenuItem( m_menuHelp, wxID_ANY, wxString( _("&Check for new version") ) , wxEmptyString, wxITEM_NORMAL ); m_menuHelp->Append( m_menuItemCheckVer ); - m_menuHelp->AppendSeparator(); + wxMenuItem* m_separator5; + m_separator5 = m_menuHelp->AppendSeparator(); m_menuItemAbout = new wxMenuItem( m_menuHelp, wxID_ABOUT, wxString( _("&About...") ) + wxT('\t') + wxT("SHIFT-F1"), wxEmptyString, wxITEM_NORMAL ); m_menuHelp->Append( m_menuItemAbout ); - m_menubar1->Append( m_menuHelp, _("&Help") ); + m_menubar1->Append( m_menuHelp, _("&Help") ); this->SetMenuBar( m_menubar1 ); @@ -186,17 +191,17 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer92; bSizer92 = new wxBoxSizer( wxVERTICAL ); - sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( m_panelTopLeft, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + sbSizerDirLeft = new wxStaticBoxSizer( new wxStaticBox( m_panelTopLeft, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); m_directoryLeft = new CustomComboBox( m_panelTopLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); - sbSizer2->Add( m_directoryLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizerDirLeft->Add( m_directoryLeft, 1, wxALIGN_CENTER_VERTICAL, 5 ); m_dirPickerLeft = new wxDirPickerCtrl( m_panelTopLeft, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); m_dirPickerLeft->SetToolTip( _("Select a folder") ); - sbSizer2->Add( m_dirPickerLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizerDirLeft->Add( m_dirPickerLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer92->Add( sbSizer2, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + bSizer92->Add( sbSizerDirLeft, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); m_panelTopLeft->SetSizer( bSizer92 ); m_panelTopLeft->Layout(); @@ -255,32 +260,31 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer77; bSizer77 = new wxBoxSizer( wxHORIZONTAL ); - wxStaticBoxSizer* sbSizer3; - sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelTopRight, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); + sbSizerDirRight = new wxStaticBoxSizer( new wxStaticBox( m_panelTopRight, wxID_ANY, _("Drag && drop") ), wxHORIZONTAL ); m_bpButtonAddPair = new wxBitmapButton( m_panelTopRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 19,21 ), wxBU_AUTODRAW ); m_bpButtonAddPair->SetToolTip( _("Add folder pair") ); m_bpButtonAddPair->SetToolTip( _("Add folder pair") ); - sbSizer3->Add( m_bpButtonAddPair, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3 ); + sbSizerDirRight->Add( m_bpButtonAddPair, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3 ); m_bpButtonRemovePair = new wxBitmapButton( m_panelTopRight, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 19,21 ), wxBU_AUTODRAW ); m_bpButtonRemovePair->SetToolTip( _("Remove folder pair") ); m_bpButtonRemovePair->SetToolTip( _("Remove folder pair") ); - sbSizer3->Add( m_bpButtonRemovePair, 0, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizerDirRight->Add( m_bpButtonRemovePair, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_directoryRight = new CustomComboBox( m_panelTopRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); - sbSizer3->Add( m_directoryRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizerDirRight->Add( m_directoryRight, 1, wxALIGN_CENTER_VERTICAL, 5 ); m_dirPickerRight = new wxDirPickerCtrl( m_panelTopRight, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, 0 ); m_dirPickerRight->SetToolTip( _("Select a folder") ); - sbSizer3->Add( m_dirPickerRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); + sbSizerDirRight->Add( m_dirPickerRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer77->Add( sbSizer3, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); + bSizer77->Add( sbSizerDirRight, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 3 ); bSizer94->Add( bSizer77, 0, wxEXPAND|wxLEFT, 3 ); @@ -464,7 +468,6 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer23 = new wxBoxSizer( wxVERTICAL ); m_checkBoxHideFilt = new wxCheckBox( m_panelFilter, wxID_ANY, _("Hide excluded items"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxHideFilt->SetToolTip( _("Hide filtered or temporarily excluded files") ); bSizer23->Add( m_checkBoxHideFilt, 0, wxEXPAND, 5 ); @@ -781,13 +784,13 @@ MainDialogGenerated::~MainDialogGenerated() this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnNewConfig ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); + this->Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuGlobalSettings ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuBatchJob ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuExportFileList ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnShowHelp ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuCheckVersion ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) ); + this->Disconnect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) ); m_buttonCompare->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this ); m_bpButtonCmpConfig->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCmpSettings ), NULL, this ); m_bpButtonSyncConfig->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), NULL, this ); @@ -829,6 +832,7 @@ MainDialogGenerated::~MainDialogGenerated() m_bpButtonSyncCreateRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncCreateRight ), NULL, this ); m_bpButtonConflict->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConflictFiles ), NULL, this ); m_bpButton10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnQuit ), NULL, this ); + } FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) @@ -1313,7 +1317,6 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS sbSizer24->Add( 0, 0, 1, wxEXPAND, 5 ); m_checkBoxSilent = new wxCheckBox( m_panelOverview, wxID_ANY, _("Silent mode"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxSilent->SetToolTip( _("Run minimized and write status information to a logfile") ); sbSizer24->Add( m_checkBoxSilent, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 14 ); @@ -1433,6 +1436,7 @@ BatchDlgGenerated::~BatchDlgGenerated() m_buttonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this ); m_buttonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLoadBatchJob ), NULL, this ); m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); + } CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) @@ -1572,7 +1576,7 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, bSizer48->Add( m_staticText30, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); m_textCtrlStatus = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); - m_textCtrlStatus->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrlStatus->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer48->Add( m_textCtrlStatus, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -1936,6 +1940,7 @@ SyncCfgDlgGenerated::~SyncCfgDlgGenerated() m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncCfgDlgGenerated::OnRightNewer ), NULL, this ); m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncCfgDlgGenerated::OnDifferent ), NULL, this ); m_bpButtonConflict->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncCfgDlgGenerated::OnConflict ), NULL, this ); + } CmpCfgDlgGenerated::CmpCfgDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2062,6 +2067,7 @@ CmpCfgDlgGenerated::~CmpCfgDlgGenerated() m_choiceHandleSymlinks->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( CmpCfgDlgGenerated::OnChangeErrorHandling ), NULL, this ); m_button10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CmpCfgDlgGenerated::OnOkay ), NULL, this ); m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CmpCfgDlgGenerated::OnCancel ), NULL, this ); + } SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) @@ -2078,26 +2084,6 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, wxBoxSizer* bSizer37; bSizer37 = new wxBoxSizer( wxHORIZONTAL ); - m_animationControl1 = new wxAnimationCtrl(this, wxID_ANY, wxNullAnimation, wxDefaultPosition, wxSize( 45,45 )); - bSizer37->Add( m_animationControl1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - m_panel8 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER|wxTAB_TRAVERSAL ); - m_panel8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT ) ); - - wxBoxSizer* bSizer72; - bSizer72 = new wxBoxSizer( wxVERTICAL ); - - m_staticText56 = new wxStaticText( m_panel8, wxID_ANY, _("Synchronization status"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText56->Wrap( -1 ); - m_staticText56->SetFont( wxFont( 16, 70, 90, 92, false, wxEmptyString ) ); - - bSizer72->Add( m_staticText56, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); - - m_panel8->SetSizer( bSizer72 ); - m_panel8->Layout(); - bSizer72->Fit( m_panel8 ); - bSizer37->Add( m_panel8, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - bSizer27->Add( bSizer37, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); wxBoxSizer* bSizer42; @@ -2111,10 +2097,13 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, m_staticTextStatus = new wxStaticText( this, wxID_ANY, _("Synchronizing..."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextStatus->Wrap( -1 ); - m_staticTextStatus->SetFont( wxFont( 14, 70, 93, 90, false, wxEmptyString ) ); + m_staticTextStatus->SetFont( wxFont( 14, 70, 90, 92, false, wxEmptyString ) ); bSizer42->Add( m_staticTextStatus, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); + m_animationControl1 = new wxAnimationCtrl(this, wxID_ANY, wxNullAnimation, wxDefaultPosition, wxSize( 45,45 )); + bSizer42->Add( m_animationControl1, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); @@ -2218,7 +2207,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, bSizer27->Add( bSizer31, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); m_textCtrlInfo = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY ); - m_textCtrlInfo->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrlInfo->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer27->Add( m_textCtrlInfo, 3, wxEXPAND|wxALL, 5 ); @@ -2308,6 +2297,7 @@ SyncStatusDlgGenerated::~SyncStatusDlgGenerated() m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncStatusDlgGenerated::OnOkay ), NULL, this ); m_buttonPause->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncStatusDlgGenerated::OnPause ), NULL, this ); m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncStatusDlgGenerated::OnAbort ), NULL, this ); + } HelpDlgGenerated::HelpDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2482,6 +2472,7 @@ HelpDlgGenerated::~HelpDlgGenerated() // Disconnect Events this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( HelpDlgGenerated::OnClose ) ); m_button8->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( HelpDlgGenerated::OnOK ), NULL, this ); + } AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2522,7 +2513,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_scrolledWindowCodeInfo = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDOUBLE_BORDER|wxHSCROLL|wxVSCROLL ); m_scrolledWindowCodeInfo->SetScrollRate( 5, 5 ); - m_scrolledWindowCodeInfo->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_scrolledWindowCodeInfo->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); m_scrolledWindowCodeInfo->SetMinSize( wxSize( -1,120 ) ); bSizerCodeInfo = new wxBoxSizer( wxVERTICAL ); @@ -2539,6 +2530,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_hyperlink21 = new wxHyperlinkCtrl( m_scrolledWindowCodeInfo, wxID_ANY, _("- ZenJu -"), wxT("mailto:zhnmju123@gmx.de"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); m_hyperlink21->SetFont( wxFont( 10, 74, 93, 92, false, wxT("Segoe Print") ) ); + m_hyperlink21->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); m_hyperlink21->SetToolTip( _("zhnmju123@gmx.de") ); bSizerCodeInfo->Add( m_hyperlink21, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -2550,7 +2542,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_scrolledWindowTranslators = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxDOUBLE_BORDER|wxHSCROLL|wxVSCROLL ); m_scrolledWindowTranslators->SetScrollRate( 5, 5 ); - m_scrolledWindowTranslators->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_scrolledWindowTranslators->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); m_scrolledWindowTranslators->SetMinSize( wxSize( -1,140 ) ); m_scrolledWindowTranslators->SetMaxSize( wxSize( -1,145 ) ); @@ -2692,6 +2684,7 @@ AboutDlgGenerated::~AboutDlgGenerated() // Disconnect Events this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( AboutDlgGenerated::OnClose ) ); m_buttonOkay->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnOK ), NULL, this ); + } ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2711,14 +2704,13 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); - m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); m_checkBoxIgnoreErrors = new wxCheckBox( this, wxID_ANY, _("Ignore subsequent errors"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxIgnoreErrors->SetToolTip( _("Hide further error messages during the current process") ); bSizer24->Add( m_checkBoxIgnoreErrors, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 10 ); @@ -2767,6 +2759,7 @@ ErrorDlgGenerated::~ErrorDlgGenerated() m_buttonIgnore->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnIgnore ), NULL, this ); m_buttonRetry->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this ); m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this ); + } WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2786,14 +2779,13 @@ WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); - m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); m_checkBoxDontShowAgain = new wxCheckBox( this, wxID_ANY, _("Do not show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer24->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 10 ); @@ -2840,6 +2832,7 @@ WarningDlgGenerated::~WarningDlgGenerated() m_buttonIgnore->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnIgnore ), NULL, this ); m_buttonSwitch->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnSwitch ), NULL, this ); m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this ); + } QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2859,14 +2852,13 @@ QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, con bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); - m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrl8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); m_checkBoxDontAskAgain = new wxCheckBox( this, wxID_ANY, _("Do not show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer24->Add( m_checkBoxDontAskAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 10 ); @@ -2913,6 +2905,7 @@ QuestionDlgGenerated::~QuestionDlgGenerated() m_buttonYes->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnYes ), NULL, this ); m_buttonNo->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnNo ), NULL, this ); m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnCancel ), NULL, this ); + } DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2949,7 +2942,6 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer99 = new wxBoxSizer( wxHORIZONTAL ); m_checkBoxDeleteBothSides = new wxCheckBox( this, wxID_ANY, _("Delete on both sides"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxDeleteBothSides->SetToolTip( _("Delete on both sides even if the file is selected on one side only") ); bSizer99->Add( m_checkBoxDeleteBothSides, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -2958,14 +2950,13 @@ DeleteDlgGenerated::DeleteDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer99->Add( 0, 0, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); m_checkBoxUseRecycler = new wxCheckBox( this, wxID_ANY, _("Use Recycle Bin"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxUseRecycler->SetValue(true); - + m_checkBoxUseRecycler->SetValue(true); bSizer99->Add( m_checkBoxUseRecycler, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); bSizer24->Add( bSizer99, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 10 ); m_textCtrlMessage = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); - m_textCtrlMessage->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) ); + m_textCtrlMessage->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) ); bSizer24->Add( m_textCtrlMessage, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); @@ -3004,6 +2995,7 @@ DeleteDlgGenerated::~DeleteDlgGenerated() m_checkBoxUseRecycler->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DeleteDlgGenerated::OnUseRecycler ), NULL, this ); m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DeleteDlgGenerated::OnOK ), NULL, this ); m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DeleteDlgGenerated::OnCancel ), NULL, this ); + } FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -3217,6 +3209,7 @@ FilterDlgGenerated::~FilterDlgGenerated() m_button9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnDefault ), NULL, this ); m_button10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnApply ), NULL, this ); m_button17->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this ); + } CustomizeColsDlgGenerated::CustomizeColsDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -3300,6 +3293,7 @@ CustomizeColsDlgGenerated::~CustomizeColsDlgGenerated() m_button9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CustomizeColsDlgGenerated::OnDefault ), NULL, this ); m_button28->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CustomizeColsDlgGenerated::OnOkay ), NULL, this ); m_button29->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CustomizeColsDlgGenerated::OnCancel ), NULL, this ); + } GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -3343,20 +3337,12 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind wxStaticBoxSizer* sbSizer23; sbSizer23 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxVERTICAL ); - m_checkBoxIgnoreOneHour = new wxCheckBox( this, wxID_ANY, _("Ignore 1-hour file time difference"), wxDefaultPosition, wxDefaultSize, 0 ); - - m_checkBoxIgnoreOneHour->SetToolTip( _("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") ); - - sbSizer23->Add( m_checkBoxIgnoreOneHour, 0, wxALL|wxEXPAND, 5 ); - m_checkBoxCopyLocked = new wxCheckBox( this, wxID_ANY, _("Copy locked files"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxCopyLocked->SetToolTip( _("Copy shared or locked files using Volume Shadow Copy Service\n(Requires Administrator rights)") ); sbSizer23->Add( m_checkBoxCopyLocked, 0, wxALL|wxEXPAND, 5 ); m_checkBoxCopyPermissions = new wxCheckBox( this, wxID_ANY, _("Copy filesystem permissions"), wxDefaultPosition, wxDefaultSize, 0 ); - m_checkBoxCopyPermissions->SetToolTip( _("Transfer file and directory permissions\n(Requires Administrator rights)") ); sbSizer23->Add( m_checkBoxCopyPermissions, 0, wxALL|wxEXPAND, 5 ); @@ -3487,6 +3473,7 @@ GlobalSettingsDlgGenerated::~GlobalSettingsDlgGenerated() m_button9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GlobalSettingsDlgGenerated::OnDefault ), NULL, this ); m_buttonOkay->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GlobalSettingsDlgGenerated::OnOkay ), NULL, this ); m_button29->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GlobalSettingsDlgGenerated::OnCancel ), NULL, this ); + } SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -3659,7 +3646,6 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i bSizer142 = new wxBoxSizer( wxHORIZONTAL ); m_checkBoxDontShowAgain = new wxCheckBox( this, wxID_ANY, _("Do not show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer142->Add( m_checkBoxDontShowAgain, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -3688,6 +3674,7 @@ SyncPreviewDlgGenerated::~SyncPreviewDlgGenerated() this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncPreviewDlgGenerated::OnClose ) ); m_buttonStartSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncPreviewDlgGenerated::OnStartSync ), NULL, this ); m_button16->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncPreviewDlgGenerated::OnCancel ), NULL, this ); + } PopupFrameGenerated1::PopupFrameGenerated1( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) @@ -3740,8 +3727,7 @@ SearchDialogGenerated::SearchDialogGenerated( wxWindow* parent, wxWindowID id, c bSizer166->Add( 0, 10, 0, 0, 5 ); m_checkBoxMatchCase = new wxCheckBox( this, wxID_ANY, _("Match case"), wxDefaultPosition, wxDefaultSize, 0 ); - - bSizer166->Add( m_checkBoxMatchCase, 0, wxALL|wxEXPAND, 5 ); + bSizer166->Add( m_checkBoxMatchCase, 0, wxALL, 5 ); bSizer161->Add( bSizer166, 1, wxALIGN_CENTER_VERTICAL, 5 ); @@ -3779,4 +3765,5 @@ SearchDialogGenerated::~SearchDialogGenerated() m_textCtrlSearchTxt->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( SearchDialogGenerated::OnText ), NULL, this ); m_buttonFindNext->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SearchDialogGenerated::OnFindNext ), NULL, this ); m_button29->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SearchDialogGenerated::OnCancel ), NULL, this ); + } diff --git a/ui/gui_generated.h b/ui/gui_generated.h index 96ede3c4..22bddfb1 100644 --- a/ui/gui_generated.h +++ b/ui/gui_generated.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Apr 16 2008) +// C++ code generated with wxFormBuilder (version Sep 8 2010) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -92,7 +92,7 @@ class MainDialogGenerated : public wxFrame wxBitmapButton* m_bpButtonSyncConfig; wxButtonWithImage* m_buttonStartSync; - wxStaticBoxSizer* sbSizer2; + wxStaticBoxSizer* sbSizerDirLeft; wxPanel* m_panelTopMiddle; wxBoxSizer* bSizerMiddle; @@ -100,6 +100,7 @@ class MainDialogGenerated : public wxFrame + wxStaticBoxSizer* sbSizerDirRight; wxBitmapButton* m_bpButtonAddPair; wxScrolledWindow* m_scrolledWindowFolderPairs; wxBoxSizer* bSizerAddFolderPairs; @@ -162,55 +163,55 @@ class MainDialogGenerated : public wxFrame wxStaticBitmap* m_bitmap15; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnCompare( wxCommandEvent& event ){ event.Skip(); } - virtual void OnStartSync( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSwitchView( wxCommandEvent& event ){ event.Skip(); } - virtual void OnNewConfig( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSaveConfig( wxCommandEvent& event ){ event.Skip(); } - virtual void OnLoadConfig( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuQuit( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuGlobalSettings( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuBatchJob( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuExportFileList( wxCommandEvent& event ){ event.Skip(); } - virtual void OnShowHelp( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuCheckVersion( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMenuAbout( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCmpSettings( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncSettings( wxCommandEvent& event ){ event.Skip(); } - virtual void OnDirSelected( wxFileDirPickerEvent& event ){ event.Skip(); } - virtual void OnSwapSides( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAddFolderPair( wxCommandEvent& event ){ event.Skip(); } - virtual void OnRemoveTopFolderPair( wxCommandEvent& event ){ event.Skip(); } - virtual void OnLeftGridDoubleClick( wxGridEvent& event ){ event.Skip(); } - virtual void OnContextRim( wxGridEvent& event ){ event.Skip(); } - virtual void OnSortLeftGrid( wxGridEvent& event ){ event.Skip(); } - virtual void OnContextRimLabelLeft( wxGridEvent& event ){ event.Skip(); } - virtual void OnContextMiddle( wxGridEvent& event ){ event.Skip(); } - virtual void OnSortMiddleGrid( wxGridEvent& event ){ event.Skip(); } - virtual void OnContextMiddleLabel( wxGridEvent& event ){ event.Skip(); } - virtual void OnRightGridDoubleClick( wxGridEvent& event ){ event.Skip(); } - virtual void OnSortRightGrid( wxGridEvent& event ){ event.Skip(); } - virtual void OnContextRimLabelRight( wxGridEvent& event ){ event.Skip(); } - virtual void OnCfgHistoryKeyEvent( wxKeyEvent& event ){ event.Skip(); } - virtual void OnLoadFromHistory( wxCommandEvent& event ){ event.Skip(); } - virtual void OnConfigureFilter( 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 OnSyncDeleteRight( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncDirRight( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncCreateRight( wxCommandEvent& event ){ event.Skip(); } - virtual void OnConflictFiles( wxCommandEvent& event ){ event.Skip(); } - virtual void OnQuit( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnCompare( wxCommandEvent& event ) { event.Skip(); } + virtual void OnStartSync( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSwitchView( wxCommandEvent& event ) { event.Skip(); } + virtual void OnNewConfig( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSaveConfig( wxCommandEvent& event ) { event.Skip(); } + virtual void OnLoadConfig( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuQuit( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuGlobalSettings( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuBatchJob( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuExportFileList( wxCommandEvent& event ) { event.Skip(); } + virtual void OnShowHelp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuCheckVersion( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMenuAbout( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCmpSettings( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncSettings( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDirSelected( wxFileDirPickerEvent& event ) { event.Skip(); } + virtual void OnSwapSides( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddFolderPair( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveTopFolderPair( wxCommandEvent& event ) { event.Skip(); } + virtual void OnLeftGridDoubleClick( wxGridEvent& event ) { event.Skip(); } + virtual void OnContextRim( wxGridEvent& event ) { event.Skip(); } + virtual void OnSortLeftGrid( wxGridEvent& event ) { event.Skip(); } + virtual void OnContextRimLabelLeft( wxGridEvent& event ) { event.Skip(); } + virtual void OnContextMiddle( wxGridEvent& event ) { event.Skip(); } + virtual void OnSortMiddleGrid( wxGridEvent& event ) { event.Skip(); } + virtual void OnContextMiddleLabel( wxGridEvent& event ) { event.Skip(); } + virtual void OnRightGridDoubleClick( wxGridEvent& event ) { event.Skip(); } + virtual void OnSortRightGrid( wxGridEvent& event ) { event.Skip(); } + virtual void OnContextRimLabelRight( wxGridEvent& event ) { event.Skip(); } + virtual void OnCfgHistoryKeyEvent( wxKeyEvent& event ) { event.Skip(); } + virtual void OnLoadFromHistory( wxCommandEvent& event ) { event.Skip(); } + virtual void OnConfigureFilter( 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 OnSyncDeleteRight( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncDirRight( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncCreateRight( wxCommandEvent& event ) { event.Skip(); } + virtual void OnConflictFiles( wxCommandEvent& event ) { event.Skip(); } + virtual void OnQuit( wxCommandEvent& event ) { event.Skip(); } public: @@ -225,6 +226,7 @@ class MainDialogGenerated : public wxFrame wxDirPickerCtrl* m_dirPickerRight; wxPanel* m_panelLeft; wxPanel* m_panelRight; + MainDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 933,612 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); ~MainDialogGenerated(); @@ -254,6 +256,7 @@ class FolderPairGenerated : public wxPanel wxBitmapButton* m_bpButtonRemovePair; wxTextCtrl* m_directoryRight; wxDirPickerCtrl* m_dirPickerRight; + FolderPairGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); ~FolderPairGenerated(); @@ -282,6 +285,7 @@ class BatchFolderPairGenerated : public wxPanel wxTextCtrl* m_directoryRight; wxDirPickerCtrl* m_dirPickerRight; wxBitmapButton* m_bpButtonAltSyncCfg; + BatchFolderPairGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); ~BatchFolderPairGenerated(); @@ -337,18 +341,18 @@ class BatchDlgGenerated : public wxDialog wxButton* m_button6; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnHelp( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCmpSettings( wxCommandEvent& event ){ event.Skip(); } - virtual void OnConfigureFilter( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncSettings( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAddFolderPair( wxCommandEvent& event ){ event.Skip(); } - virtual void OnRemoveTopFolderPair( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCheckSilent( wxCommandEvent& event ){ event.Skip(); } - virtual void OnChangeErrorHandling( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSaveBatchJob( wxCommandEvent& event ){ event.Skip(); } - virtual void OnLoadBatchJob( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnHelp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCmpSettings( wxCommandEvent& event ) { event.Skip(); } + virtual void OnConfigureFilter( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncSettings( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddFolderPair( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveTopFolderPair( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCheckSilent( wxCommandEvent& event ) { event.Skip(); } + virtual void OnChangeErrorHandling( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSaveBatchJob( wxCommandEvent& event ) { event.Skip(); } + virtual void OnLoadBatchJob( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: @@ -363,6 +367,7 @@ class BatchDlgGenerated : public wxDialog wxTextCtrl* m_directoryRight; wxDirPickerCtrl* m_dirPickerRight; wxBitmapButton* m_bpButtonAltSyncCfg; + BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Create a batch job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~BatchDlgGenerated(); @@ -402,6 +407,7 @@ class CompareStatusGenerated : public wxPanel wxGauge* m_gauge2; public: + CompareStatusGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL ); ~CompareStatusGenerated(); @@ -467,24 +473,25 @@ class SyncCfgDlgGenerated : public wxDialog wxBitmapButton* m_bpButtonConflict; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnSyncAutomatic( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncLeftToRight( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncUpdate( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSyncCustom( wxCommandEvent& event ){ event.Skip(); } - virtual void OnChangeErrorHandling( wxCommandEvent& event ){ event.Skip(); } - virtual void OnChangeDeletionHandling( wxCommandEvent& event ){ event.Skip(); } - virtual void OnApply( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } - virtual void OnExLeftSideOnly( wxCommandEvent& event ){ event.Skip(); } - virtual void OnExRightSideOnly( wxCommandEvent& event ){ event.Skip(); } - virtual void OnLeftNewer( wxCommandEvent& event ){ event.Skip(); } - virtual void OnRightNewer( wxCommandEvent& event ){ event.Skip(); } - virtual void OnDifferent( wxCommandEvent& event ){ event.Skip(); } - virtual void OnConflict( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnSyncAutomatic( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncLeftToRight( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncUpdate( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSyncCustom( wxCommandEvent& event ) { event.Skip(); } + virtual void OnChangeErrorHandling( wxCommandEvent& event ) { event.Skip(); } + virtual void OnChangeDeletionHandling( wxCommandEvent& event ) { event.Skip(); } + virtual void OnApply( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } + virtual void OnExLeftSideOnly( wxCommandEvent& event ) { event.Skip(); } + virtual void OnExRightSideOnly( wxCommandEvent& event ) { event.Skip(); } + virtual void OnLeftNewer( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRightNewer( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDifferent( wxCommandEvent& event ) { event.Skip(); } + virtual void OnConflict( wxCommandEvent& event ) { event.Skip(); } public: + SyncCfgDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Synchronization settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); ~SyncCfgDlgGenerated(); @@ -512,16 +519,17 @@ class CmpCfgDlgGenerated : public wxDialog wxButton* m_button6; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnTimeSize( wxCommandEvent& event ){ event.Skip(); } - virtual void OnContent( wxCommandEvent& event ){ event.Skip(); } - virtual void OnShowHelp( wxCommandEvent& event ){ event.Skip(); } - virtual void OnChangeErrorHandling( wxCommandEvent& event ){ event.Skip(); } - virtual void OnOkay( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnTimeSize( wxCommandEvent& event ) { event.Skip(); } + virtual void OnContent( wxCommandEvent& event ) { event.Skip(); } + virtual void OnShowHelp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnChangeErrorHandling( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + CmpCfgDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Comparison settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); ~CmpCfgDlgGenerated(); @@ -536,12 +544,10 @@ class SyncStatusDlgGenerated : public wxFrame protected: - wxAnimationCtrl* m_animationControl1; - wxPanel* m_panel8; - wxStaticText* m_staticText56; wxStaticBitmap* m_bitmapStatus; wxStaticText* m_staticTextStatus; + wxAnimationCtrl* m_animationControl1; wxBoxSizer* bSizer31; wxBoxSizer* bSizerObjectsRemaining; @@ -575,16 +581,17 @@ class SyncStatusDlgGenerated : public wxFrame // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnIconize( wxIconizeEvent& event ){ event.Skip(); } - virtual void OnOkay( wxCommandEvent& event ){ event.Skip(); } - virtual void OnPause( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAbort( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnIconize( wxIconizeEvent& event ) { event.Skip(); } + virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } + virtual void OnPause( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); } public: wxGauge* m_gauge1; - SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 638,376 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); + + SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 638,350 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); ~SyncStatusDlgGenerated(); }; @@ -629,11 +636,12 @@ class HelpDlgGenerated : public wxDialog wxButton* m_button8; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnOK( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } public: + HelpDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 579,543 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~HelpDlgGenerated(); @@ -682,11 +690,12 @@ class AboutDlgGenerated : public wxDialog wxButton* m_buttonOkay; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnOK( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } public: + AboutDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); ~AboutDlgGenerated(); @@ -711,13 +720,14 @@ class ErrorDlgGenerated : public wxDialog // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnIgnore( wxCommandEvent& event ){ event.Skip(); } - virtual void OnRetry( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAbort( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnIgnore( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRetry( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); } public: + ErrorDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Error"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 421,228 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~ErrorDlgGenerated(); @@ -741,14 +751,15 @@ class WarningDlgGenerated : public wxDialog // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnIgnore( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSwitch( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAbort( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnIgnore( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSwitch( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); } public: wxStaticBitmap* m_bitmap10; + WarningDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Warning"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 421,231 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~WarningDlgGenerated(); @@ -773,13 +784,14 @@ class QuestionDlgGenerated : public wxDialog // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnYes( wxCommandEvent& event ){ event.Skip(); } - virtual void OnNo( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnYes( wxCommandEvent& event ) { event.Skip(); } + virtual void OnNo( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + QuestionDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Question"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 420,198 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~QuestionDlgGenerated(); @@ -806,14 +818,15 @@ class DeleteDlgGenerated : public wxDialog wxButton* m_buttonCancel; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnDelOnBothSides( wxCommandEvent& event ){ event.Skip(); } - virtual void OnUseRecycler( wxCommandEvent& event ){ event.Skip(); } - virtual void OnOK( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnDelOnBothSides( wxCommandEvent& event ) { event.Skip(); } + virtual void OnUseRecycler( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + DeleteDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Confirm"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 553,336 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DeleteDlgGenerated(); @@ -857,14 +870,15 @@ class FilterDlgGenerated : public wxDialog wxButton* m_button17; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnHelp( wxCommandEvent& event ){ event.Skip(); } - virtual void OnDefault( wxCommandEvent& event ){ event.Skip(); } - virtual void OnApply( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnHelp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDefault( wxCommandEvent& event ) { event.Skip(); } + virtual void OnApply( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + FilterDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Configure filter"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~FilterDlgGenerated(); @@ -887,15 +901,16 @@ class CustomizeColsDlgGenerated : public wxDialog wxButton* m_button29; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnMoveUp( wxCommandEvent& event ){ event.Skip(); } - virtual void OnMoveDown( wxCommandEvent& event ){ event.Skip(); } - virtual void OnDefault( wxCommandEvent& event ){ event.Skip(); } - virtual void OnOkay( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnMoveUp( wxCommandEvent& event ) { event.Skip(); } + virtual void OnMoveDown( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDefault( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + CustomizeColsDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Customize columns"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); ~CustomizeColsDlgGenerated(); @@ -914,7 +929,6 @@ class GlobalSettingsDlgGenerated : public wxDialog wxPanel* m_panel8; wxStaticText* m_staticText56; - wxCheckBox* m_checkBoxIgnoreOneHour; wxCheckBox* m_checkBoxCopyLocked; wxCheckBox* m_checkBoxCopyPermissions; wxStaticLine* m_staticline10; @@ -933,16 +947,17 @@ class GlobalSettingsDlgGenerated : public wxDialog wxButton* m_button29; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnResetDialogs( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAddRow( wxCommandEvent& event ){ event.Skip(); } - virtual void OnRemoveRow( wxCommandEvent& event ){ event.Skip(); } - virtual void OnDefault( wxCommandEvent& event ){ event.Skip(); } - virtual void OnOkay( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnResetDialogs( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAddRow( wxCommandEvent& event ) { event.Skip(); } + virtual void OnRemoveRow( wxCommandEvent& event ) { event.Skip(); } + virtual void OnDefault( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + GlobalSettingsDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Global settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~GlobalSettingsDlgGenerated(); @@ -983,12 +998,13 @@ class SyncPreviewDlgGenerated : public wxDialog wxButton* m_button16; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnStartSync( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnStartSync( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Synchronization Preview"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); ~SyncPreviewDlgGenerated(); @@ -1006,6 +1022,7 @@ class PopupFrameGenerated1 : public wxFrame public: wxStaticBitmap* m_bitmapLeft; wxStaticText* m_staticTextMain; + PopupFrameGenerated1( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxFRAME_NO_TASKBAR|wxSTAY_ON_TOP|wxSTATIC_BORDER ); ~PopupFrameGenerated1(); @@ -1027,13 +1044,14 @@ class SearchDialogGenerated : public wxDialog wxButton* m_button29; // Virtual event handlers, overide them in your derived class - virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnText( wxCommandEvent& event ){ event.Skip(); } - virtual void OnFindNext( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnText( wxCommandEvent& event ) { event.Skip(); } + virtual void OnFindNext( wxCommandEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } public: + SearchDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Find"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE ); ~SearchDialogGenerated(); diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp index 052c18bd..81f4de6e 100644 --- a/ui/gui_status_handler.cpp +++ b/ui/gui_status_handler.cpp @@ -79,7 +79,7 @@ void CompareStatusHandler::OnKeyPressed(wxKeyEvent& event) } -void CompareStatusHandler::updateStatusText(const Zstring& text) +void CompareStatusHandler::reportInfo(const Zstring& text) { mainDialog->compareStatus->setStatusText_NoUpdate(text); } @@ -267,7 +267,7 @@ SyncStatusHandler::~SyncStatusHandler() inline -void SyncStatusHandler::updateStatusText(const Zstring& text) +void SyncStatusHandler::reportInfo(const Zstring& text) { syncStatusFrame.setStatusText_NoUpdate(text); } @@ -378,7 +378,7 @@ void SyncStatusHandler::reportWarning(const wxString& warningMessage, bool& warn } -void SyncStatusHandler::reportInfo(const wxString& infoMessage) +void SyncStatusHandler::logInfo(const wxString& infoMessage) { errorLog.logInfo(infoMessage); } diff --git a/ui/gui_status_handler.h b/ui/gui_status_handler.h index d519b142..d6c03399 100644 --- a/ui/gui_status_handler.h +++ b/ui/gui_status_handler.h @@ -25,9 +25,9 @@ public: CompareStatusHandler(MainDialog* dlg); ~CompareStatusHandler(); - virtual void updateStatusText(const Zstring& text); virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void reportInfo(const Zstring& text); virtual void forceUiRefresh(); virtual ErrorHandler::Response reportError(const wxString& text); @@ -51,15 +51,15 @@ public: SyncStatusHandler(wxTopLevelWindow* parentDlg, bool ignoreAllErrors); ~SyncStatusHandler(); - virtual void updateStatusText(const Zstring& text); virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed); + virtual void reportInfo(const Zstring& text); virtual void forceUiRefresh(); virtual ErrorHandler::Response reportError(const wxString& text); virtual void reportFatalError(const wxString& errorMessage); virtual void reportWarning(const wxString& warningMessage, bool& warningActive); - void reportInfo(const wxString& infoMessage); + void logInfo(const wxString& infoMessage); private: virtual void abortThisProcess(); diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp index cc9568fb..0f2c83b5 100644 --- a/ui/main_dlg.cpp +++ b/ui/main_dlg.cpp @@ -30,7 +30,7 @@ #include "mouse_move_dlg.h" #include "progress_indicator.h" #include "msg_popup.h" -#include "../shared/drag_n_drop.h" +#include "../shared/dir_name.h" #include "../library/filter.h" #include "../structures.h" #include <wx/imaglist.h> @@ -56,16 +56,16 @@ using namespace ffs3; using ffs3::CustomLocale; -class MainFolderDragDrop : public DragDropOnMainDlg +class DirectoryNameMainImpl : public DirectoryNameMainDlg { public: - MainFolderDragDrop(MainDialog& mainDlg, - wxWindow* dropWindow1, - wxWindow* dropWindow2, - wxDirPickerCtrl* dirPicker, - wxComboBox* dirName) : - - DragDropOnMainDlg(dropWindow1, dropWindow2, dirPicker, dirName), + DirectoryNameMainImpl(MainDialog& mainDlg, + wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName, + wxStaticBoxSizer* staticBox) : + DirectoryNameMainDlg(dropWindow1, dropWindow2, dirPicker, dirName, staticBox), mainDlg_(mainDlg) {} virtual bool AcceptDrop(const std::vector<wxString>& droppedFiles) @@ -114,7 +114,7 @@ public: } case xmlAccess::MERGE_OTHER: - //=> return true: change directory selection via drag and drop + //=> return true: change directory selection via drag and drop break; } @@ -130,7 +130,8 @@ public: } private: - MainFolderDragDrop(const MainFolderDragDrop&); + DirectoryNameMainImpl(const DirectoryNameMainImpl&); + DirectoryNameMainImpl& operator=(const DirectoryNameMainImpl&); MainDialog& mainDlg_; }; @@ -147,7 +148,7 @@ private: /|\ /|\ _________|________ ________| | | | - FirstFolderPairCfg FolderPairPanel + DirectoryPairFirst DirectoryPair */ template <class GuiPanel> @@ -195,46 +196,78 @@ private: }; -class FolderPairPanel : - public FolderPairGenerated, //FolderPairPanel "owns" FolderPairGenerated! +class DirectoryPair : + public FolderPairGenerated, //DirectoryPair "owns" FolderPairGenerated! public FolderPairCallback<FolderPairGenerated> { public: - FolderPairPanel(wxWindow* parent, MainDialog& mainDialog) : + DirectoryPair(wxWindow* parent, MainDialog& mainDialog) : FolderPairGenerated(parent), FolderPairCallback<FolderPairGenerated>(static_cast<FolderPairGenerated&>(*this), mainDialog), //pass FolderPairGenerated part... - dragDropOnLeft( m_panelLeft, m_dirPickerLeft, m_directoryLeft), - dragDropOnRight(m_panelRight, m_dirPickerRight, m_directoryRight) {} + dirNameLeft( m_panelLeft, m_dirPickerLeft, m_directoryLeft), + dirNameRight(m_panelRight, m_dirPickerRight, m_directoryRight) {} + + void setValues(const Zstring& leftDir, const Zstring& rightDir, AltSyncCfgPtr syncCfg, const FilterConfig& filter) + { + setConfig(syncCfg, filter); + dirNameLeft.setName(leftDir); + dirNameRight.setName(rightDir); + } + Zstring getLeftDir() const + { + return dirNameLeft.getName(); + } + Zstring getRightDir() const + { + return dirNameRight.getName(); + } private: //support for drag and drop - DragDropOnDlg dragDropOnLeft; - DragDropOnDlg dragDropOnRight; + DirectoryName dirNameLeft; + DirectoryName dirNameRight; }; -class FirstFolderPairCfg : public FolderPairCallback<MainDialogGenerated> +class DirectoryPairFirst : public FolderPairCallback<MainDialogGenerated> { public: - FirstFolderPairCfg(MainDialog& mainDialog) : + DirectoryPairFirst(MainDialog& mainDialog) : FolderPairCallback<MainDialogGenerated>(mainDialog, mainDialog), //prepare drag & drop - dragDropOnLeft(mainDialog, - mainDialog.m_panelLeft, - mainDialog.m_panelTopLeft, - mainDialog.m_dirPickerLeft, - mainDialog.m_directoryLeft), - dragDropOnRight(mainDialog, - mainDialog.m_panelRight, - mainDialog.m_panelTopRight, - mainDialog.m_dirPickerRight, - mainDialog.m_directoryRight) {} + dirNameLeft(mainDialog, + mainDialog.m_panelLeft, + mainDialog.m_panelTopLeft, + mainDialog.m_dirPickerLeft, + mainDialog.m_directoryLeft, + mainDialog.sbSizerDirLeft), + dirNameRight(mainDialog, + mainDialog.m_panelRight, + mainDialog.m_panelTopRight, + mainDialog.m_dirPickerRight, + mainDialog.m_directoryRight, + mainDialog.sbSizerDirRight) {} + + void setValues(const Zstring& leftDir, const Zstring& rightDir, AltSyncCfgPtr syncCfg, const FilterConfig& filter) + { + setConfig(syncCfg, filter); + dirNameLeft.setName(leftDir); + dirNameRight.setName(rightDir); + } + Zstring getLeftDir() const + { + return dirNameLeft.getName(); + } + Zstring getRightDir() const + { + return dirNameRight.getName(); + } private: //support for drag and drop - MainFolderDragDrop dragDropOnLeft; - MainFolderDragDrop dragDropOnRight; + DirectoryNameMainImpl dirNameLeft; + DirectoryNameMainImpl dirNameRight; }; @@ -378,8 +411,12 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, updateFileIcons.reset(new IconUpdater(m_gridLeft, m_gridRight)); #ifdef FFS_WIN - moveWholeWindow.reset(new MouseMoveWindow(this)); + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + m_panel71, + m_panelBottom, + m_panelStatusBar); //ownership passed to "this" #endif + syncPreview.reset(new SyncPreview(this)); SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")); @@ -391,7 +428,7 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, ffs3::AppMainWindow::setMainWindow(this); //init handling of first folder pair - firstFolderPair.reset(new FirstFolderPairCfg(*this)); + firstFolderPair.reset(new DirectoryPairFirst(*this)); initViewFilterButtons(); @@ -431,13 +468,6 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, MenuItemUpdater updateMenuHelp(m_menuHelp); updateMenuHelp.addForUpdate(m_menuItemAbout, GlobalResources::getInstance().getImageByName(wxT("aboutSmall"))); -#ifdef FFS_WIN - //allow moving main dialog by clicking (nearly) anywhere... - moveWholeWindow->connectSourceWindow(m_panel71); - moveWholeWindow->connectSourceWindow(m_panelBottom); - moveWholeWindow->connectSourceWindow(m_panelStatusBar); -#endif - #ifdef FFS_LINUX if (!ffs3::isPortableVersion()) //disable update check for Linux installer-based version -> handled by .deb m_menuItemCheckVer->Enable(false); @@ -799,9 +829,9 @@ public: return DeleteFilesHandler::IGNORE_ERROR; //dummy return value } - virtual void deletionSuccessful() //called for each file/folder that has been deleted + virtual void deletionSuccessful(size_t deletedItems) //called for each file/folder that has been deleted { - ++deletionCount; + deletionCount += deletedItems; if (updateUiIsAllowed()) //test if specific time span between ui updates is over { @@ -875,7 +905,7 @@ void MainDialog::deleteSelectedFiles() globalSettings->gui.deleteOnBothSides, globalSettings->gui.useRecyclerForManualDeletion, getCurrentConfiguration().mainCfg, - &statusHandler); + statusHandler); } catch (ffs3::AbortThisProcess&) {} @@ -1100,10 +1130,11 @@ void MainDialog::OnResize(wxSizeEvent& event) GetSize(&width, &height); GetPosition(&x, &y); - if (width > 0 && height > 0 && x >= -200 && y >= -200) //test ALL parameters at once, since width/height are invalid if + //test ALL parameters at once, since width/height are invalid if the window is minimized (eg x,y == -32000; height = 28, width = 160) + //note: negative values for x and y are possible when using multiple monitors! + if (width > 0 && height > 0 && x >= -3360 && y >= -200) { - //the window is minimized (eg x,y == -32000; height = 28, width = 160) - widthNotMaximized = width; //however visible(!) x < 0 and y < 0 are possible with dual monitors + widthNotMaximized = width; //visible coordinates x < 0 and y < 0 are possible with dual monitors! heightNotMaximized = height; posXNotMaximized = x; @@ -1122,7 +1153,7 @@ void MainDialog::OnResizeFolderPairs(wxSizeEvent& event) { const int width = m_panelTopLeft->GetSize().GetWidth(); - for (std::vector<FolderPairPanel*>::iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<DirectoryPair*>::iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) (*i)->m_panelLeft->SetMinSize(wxSize(width, -1)); } @@ -1477,9 +1508,9 @@ void MainDialog::OnContextRim(wxGridEvent& event) if (exFilterCandidateObj.size() > 0 && !exFilterCandidateObj[0].isDir) { const Zstring filename = exFilterCandidateObj[0].relativeName.AfterLast(common::FILE_NAME_SEPARATOR); - if (filename.Find(wxChar('.'), false) != Zstring::npos) //be careful: AfterLast would return the whole string if '.' were not found! + if (filename.find(Zchar('.')) != Zstring::npos) //be careful: AfterLast would return the whole string if '.' were not found! { - const Zstring extension = filename.AfterLast(DefaultChar('.')); + const Zstring extension = filename.AfterLast(Zchar('.')); //add context menu item wxMenuItem* menuItemExclExt = new wxMenuItem(contextMenu.get(), CONTEXT_EXCLUDE_EXT, wxString(_("Exclude via filter:")) + wxT(" ") + wxT("*.") + zToWx(extension)); @@ -1597,13 +1628,13 @@ void MainDialog::OnContextExcludeExtension(wxCommandEvent& event) SelectedExtension* selExtension = dynamic_cast<SelectedExtension*>(event.m_callbackUserData); if (selExtension) { - const Zstring newExclude = Zstring(DefaultStr("*.")) + selExtension->extension; + const Zstring newExclude = Zstring(Zstr("*.")) + selExtension->extension; //add to filter config Zstring& excludeFilter = currentCfg.mainCfg.globalFilter.excludeFilter; - if (!excludeFilter.empty() && !excludeFilter.EndsWith(DefaultStr(";"))) - excludeFilter += DefaultStr("\n"); - excludeFilter += newExclude + DefaultStr(";"); //';' is appended to 'mark' that next exclude extension entry won't write to new line + if (!excludeFilter.empty() && !excludeFilter.EndsWith(Zstr(";"))) + excludeFilter += Zstr("\n"); + excludeFilter += newExclude + Zstr(";"); //';' is appended to 'mark' that next exclude extension entry won't write to new line updateFilterButtons(); @@ -1633,7 +1664,7 @@ void MainDialog::OnContextExcludeObject(wxCommandEvent& event) for (std::vector<FilterObject>::const_iterator i = objCont->selectedObjects.begin(); i != objCont->selectedObjects.end(); ++i) { if (i != objCont->selectedObjects.begin()) - newExclude += DefaultStr("\n"); + newExclude += Zstr("\n"); newExclude += common::FILE_NAME_SEPARATOR + i->relativeName; if (i->isDir) @@ -1642,8 +1673,8 @@ void MainDialog::OnContextExcludeObject(wxCommandEvent& event) //add to filter config Zstring& excludeFilter = currentCfg.mainCfg.globalFilter.excludeFilter; - if (!excludeFilter.empty() && !excludeFilter.EndsWith(DefaultStr("\n"))) - excludeFilter += DefaultStr("\n"); + if (!excludeFilter.empty() && !excludeFilter.EndsWith(Zstr("\n"))) + excludeFilter += Zstr("\n"); excludeFilter += newExclude; updateFilterButtons(); @@ -2276,7 +2307,7 @@ void MainDialog::setCurrentConfiguration(const xmlAccess::XmlGuiConfig& newGuiCf inline -FolderPairEnh getEnahncedPair(const FolderPairPanel* panel) +FolderPairEnh getEnahncedPair(const DirectoryPair* panel) { return FolderPairEnh(panel->getLeftDir(), panel->getRightDir(), @@ -2319,10 +2350,12 @@ const wxString& MainDialog::lastConfigFileName() void MainDialog::refreshGridAfterFilterChange(const int delay) { //signal UI that grids need to be refreshed on next Update() - m_gridLeft->ForceRefresh(); + m_gridLeft ->ForceRefresh(); m_gridMiddle->ForceRefresh(); - m_gridRight->ForceRefresh(); - Update(); //show changes resulting from ForceRefresh() + m_gridRight ->ForceRefresh(); + m_gridLeft ->Update(); // + m_gridMiddle->Update(); //show changes resulting from ForceRefresh() + m_gridRight ->Update(); // if (currentCfg.hideFilteredElements) { @@ -2614,9 +2647,9 @@ void MainDialog::updateFilterButtons() firstFolderPair->refreshButtons(); //update folder pairs - for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<DirectoryPair*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) { - FolderPairPanel* dirPair = *i; + DirectoryPair* dirPair = *i; dirPair->refreshButtons(); } } @@ -2642,7 +2675,6 @@ void MainDialog::OnCompare(wxCommandEvent &event) //begin comparison ffs3::CompareProcess comparison(currentCfg.mainCfg.handleSymlinks, globalSettings->fileTimeTolerance, - globalSettings->ignoreOneHourDiff, globalSettings->optDialogs, &statusHandler); @@ -2710,6 +2742,8 @@ void MainDialog::OnCompare(wxCommandEvent &event) void MainDialog::updateGuiGrid() { + wxWindowUpdateLocker dummy(m_panelStatusBar); //avoid display distortion + updateGridViewData(); //update gridDataView and write status information //all three grids retrieve their data directly via gridDataView @@ -2789,9 +2823,15 @@ void MainDialog::OnCmpSettings(wxCommandEvent& event) wxPoint windowPos = m_bpButtonCmpConfig->GetScreenPosition(); windowPos.x += m_bpButtonCmpConfig->GetSize().GetWidth() + 5; + const CompareVariant compareVarOld = currentCfg.mainCfg.compareVar; + const SymLinkHandling handleSymlinksOld = currentCfg.mainCfg.handleSymlinks; + if (ffs3::showCompareCfgDialog(windowPos, currentCfg.mainCfg.compareVar, - currentCfg.mainCfg.handleSymlinks) == DefaultReturnCode::BUTTON_OKAY) + currentCfg.mainCfg.handleSymlinks) == DefaultReturnCode::BUTTON_OKAY && + //check if settings were changed at all + (compareVarOld != currentCfg.mainCfg.compareVar || + handleSymlinksOld != currentCfg.mainCfg.handleSymlinks)) { //update compare variant name m_staticTextCmpVariant->SetLabel(wxString(wxT("(")) + getVariantName(currentCfg.mainCfg.compareVar) + wxT(")")); @@ -2854,7 +2894,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event) //check if there are files/folders to be sync'ed at all if (!synchronizationNeeded(gridDataView->getDataTentative())) - statusHandler.reportInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case + statusHandler.logInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case //start synchronization and mark all elements processed ffs3::SyncProcess synchronization( @@ -2971,27 +3011,30 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event) void MainDialog::OnSortMiddleGrid(wxGridEvent& event) { - //determine direction for std::sort() - static bool sortDefault = true; - if (lastSortColumn != 0 || lastSortGrid != m_gridMiddle) - sortDefault = true; - else - sortDefault = !sortDefault; - lastSortColumn = 0; - lastSortGrid = m_gridMiddle; - - //start sort - if (syncPreview->previewIsEnabled()) - gridDataView->sortView(GridView::SORT_BY_SYNC_DIRECTION, true, sortDefault); - else - gridDataView->sortView(GridView::SORT_BY_CMP_RESULT, true, sortDefault); - - updateGuiGrid(); //refresh gridDataView - - //set sort direction indicator on UI - m_gridLeft->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); - m_gridRight->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); - m_gridMiddle->setSortMarker(CustomGrid::SortMarker(0, sortDefault ? CustomGrid::ASCENDING : CustomGrid::DESCENDING)); + //sorting middle grid is more or less useless: therefore let's toggle view instead! + syncPreview->enablePreview(!syncPreview->previewIsEnabled()); //toggle view + +// //determine direction for std::sort() +// static bool sortDefault = true; +// if (lastSortColumn != 0 || lastSortGrid != m_gridMiddle) +// sortDefault = true; +// else +// sortDefault = !sortDefault; +// lastSortColumn = 0; +// lastSortGrid = m_gridMiddle; +// +// //start sort +// if (syncPreview->previewIsEnabled()) +// gridDataView->sortView(GridView::SORT_BY_SYNC_DIRECTION, true, sortDefault); +// else +// gridDataView->sortView(GridView::SORT_BY_CMP_RESULT, true, sortDefault); +// +// updateGuiGrid(); //refresh gridDataView +// +// //set sort direction indicator on UI +// m_gridLeft->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); +// m_gridRight->setSortMarker(CustomGrid::SortMarker(-1, CustomGrid::ASCENDING)); +// m_gridMiddle->setSortMarker(CustomGrid::SortMarker(0, sortDefault ? CustomGrid::ASCENDING : CustomGrid::DESCENDING)); } @@ -3063,9 +3106,9 @@ void MainDialog::OnSwapSides(wxCommandEvent& event) firstFolderPair->getAltFilterConfig()); //additional pairs - for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<DirectoryPair*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) { - FolderPairPanel* dirPair = *i; + DirectoryPair* dirPair = *i; dirPair->setValues(dirPair->getRightDir(), // swap directories dirPair->getLeftDir(), // dirPair->getAltSyncConfig(), @@ -3428,7 +3471,7 @@ void MainDialog::OnRemoveTopFolderPair(wxCommandEvent& event) void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) { const wxObject* const eventObj = event.GetEventObject(); //find folder pair originating the event - for (std::vector<FolderPairPanel*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) + for (std::vector<DirectoryPair*>::const_iterator i = additionalFolderPairs.begin(); i != additionalFolderPairs.end(); ++i) if (eventObj == (*i)->m_bpButtonRemovePair) { removeAddFolderPair(i - additionalFolderPairs.begin()); @@ -3445,9 +3488,6 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) } -const size_t MAX_ADD_FOLDER_PAIRS = 5; - - void MainDialog::updateGuiForFolderPair() { //adapt delete top folder pair button @@ -3491,7 +3531,7 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool for (std::vector<FolderPairEnh>::const_iterator i = newPairs.begin(); i != newPairs.end(); ++i) { //add new folder pair - FolderPairPanel* newPair = new FolderPairPanel(m_scrolledWindowFolderPairs, *this); + DirectoryPair* newPair = new DirectoryPair(m_scrolledWindowFolderPairs, *this); //correct width of middle block newPair->m_panel21->SetMinSize(wxSize(m_gridMiddle->GetSize().GetWidth(), -1)); @@ -3526,7 +3566,7 @@ void MainDialog::addFolderPair(const std::vector<FolderPairEnh>& newPairs, bool } //set size of scrolled window - const size_t visiblePairs = std::min(additionalFolderPairs.size(), MAX_ADD_FOLDER_PAIRS); //up to MAX_ADD_FOLDER_PAIRS additional pairs shall be shown + const size_t visiblePairs = std::min(additionalFolderPairs.size(), globalSettings->gui.addFolderPairCountMax); //up to "addFolderPairCountMax" additional pairs shall be shown m_scrolledWindowFolderPairs->SetMinSize(wxSize( -1, pairHeight * static_cast<int>(visiblePairs))); //update controls @@ -3546,7 +3586,7 @@ void MainDialog::removeAddFolderPair(size_t pos) if (pos < additionalFolderPairs.size()) { //remove folder pairs from window - FolderPairPanel* pairToDelete = additionalFolderPairs[pos]; + DirectoryPair* pairToDelete = additionalFolderPairs[pos]; const int pairHeight = pairToDelete->GetSize().GetHeight(); bSizerAddFolderPairs->Detach(pairToDelete); //Remove() does not work on Window*, so do it manually @@ -3555,7 +3595,7 @@ void MainDialog::removeAddFolderPair(size_t pos) //set size of scrolled window const size_t additionalRows = additionalFolderPairs.size(); - if (additionalRows <= MAX_ADD_FOLDER_PAIRS) //up to MAX_ADD_FOLDER_PAIRS additional pairs shall be shown + if (additionalRows <= globalSettings->gui.addFolderPairCountMax) //up to "addFolderPairCountMax" additional pairs shall be shown m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, pairHeight * static_cast<int>(additionalRows))); //update controls @@ -3688,6 +3728,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) wxFFile output(newFileName.c_str(), wxT("w")); //don't write in binary mode if (output.IsOpened()) { + output.Write(common::BYTE_ORDER_MARK_UTF8, sizeof(common::BYTE_ORDER_MARK_UTF8) - 1); output.Write(exportString); pushStatusInformation(_("File list exported!")); } diff --git a/ui/main_dlg.h b/ui/main_dlg.h index 3e62191f..34a1fdb2 100644 --- a/ui/main_dlg.h +++ b/ui/main_dlg.h @@ -15,14 +15,14 @@ #include <set> class CompareStatusHandler; -class MainFolderDragDrop; +class DirectoryNameMainImpl; class CustomGrid; class FFSCheckRowsEvent; class FFSSyncDirectionEvent; class IconUpdater; class ManualDeletionHandler; -class FolderPairPanel; -class FirstFolderPairCfg; +class DirectoryPair; +class DirectoryPairFirst; class CompareStatus; @@ -30,7 +30,6 @@ namespace ffs3 { class CustomLocale; class GridView; -class MouseMoveWindow; } @@ -49,7 +48,8 @@ public: private: friend class CompareStatusHandler; friend class ManualDeletionHandler; - friend class MainFolderDragDrop; + friend class DirectoryPairFirst; + friend class DirectoryNameMainImpl; template <class GuiPanel> friend class FolderPairCallback; @@ -275,8 +275,8 @@ private: xmlAccess::XmlGuiConfig currentCfg; //folder pairs: - std::auto_ptr<FirstFolderPairCfg> firstFolderPair; //always bound!!! - std::vector<FolderPairPanel*> additionalFolderPairs; //additional pairs to the first pair + std::auto_ptr<DirectoryPairFirst> firstFolderPair; //always bound!!! + std::vector<DirectoryPair*> additionalFolderPairs; //additional pairs to the first pair //gui settings int widthNotMaximized; @@ -309,11 +309,6 @@ private: //update icons periodically: one updater instance for both left and right grids std::auto_ptr<IconUpdater> updateFileIcons; -#ifdef FFS_WIN - //enable moving window by clicking on sub-windows instead of header line - std::auto_ptr<ffs3::MouseMoveWindow> moveWholeWindow; -#endif - //encapsulation of handling of sync preview class SyncPreview //encapsulates MainDialog functionality for synchronization preview (friend class) { diff --git a/ui/mouse_move_dlg.cpp b/ui/mouse_move_dlg.cpp index 526408d4..efaba5fc 100644 --- a/ui/mouse_move_dlg.cpp +++ b/ui/mouse_move_dlg.cpp @@ -10,17 +10,34 @@ using namespace ffs3; -void MouseMoveWindow::connectSourceWindow(wxWindow* sourceWindow) +MouseMoveWindow::MouseMoveWindow(wxWindow& parent, + wxWindow* child1, + wxWindow* child2, + wxWindow* child3, + wxWindow* child4, + wxWindow* child5, + wxWindow* child6) : wxWindow(&parent, wxID_ANY) { - sourceWindow->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child1) child1->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child2) child2->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child3) child3->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child4) child4->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child5) child5->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + if (child6) child6->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MouseMoveWindow::LeftButtonDown), NULL, this); + + Hide(); //this is just a dummy window so that its parent can have ownership + Disable(); } void MouseMoveWindow::LeftButtonDown(wxMouseEvent& event) { + if (!GetParent()) + return; + ::ReleaseCapture(); //::SendMessage(GetHwndOf(dialogToMove_), WM_NCLBUTTONDOWN, HTCAPTION, 0); - ::SendMessage(static_cast<HWND>(dialogToMove_->GetHWND()), WM_NCLBUTTONDOWN, HTCAPTION, 0); + ::SendMessage(static_cast<HWND>(GetParent()->GetHWND()), WM_NCLBUTTONDOWN, HTCAPTION, 0); //event.Skip(); -> swallow event, to avoid other windows losing focus } diff --git a/ui/mouse_move_dlg.h b/ui/mouse_move_dlg.h index 9d68845d..c7d07629 100644 --- a/ui/mouse_move_dlg.h +++ b/ui/mouse_move_dlg.h @@ -12,24 +12,23 @@ namespace ffs3 { -//move main dialog by mouse-dragging contained sub-windows: -//---------------------------------------------------------------------------------------- -//keep it as an attribute of the to-be-moved dialog and ensure that all connected source windows -//have a longer lifetime than the dialog which is moved (should be fulfilled naturally) -class MouseMoveWindow : private wxEvtHandler +//move main dialog by mouse-dragging contained sub-windows: just attach to parent via new in constructor: ownership passed! +class MouseMoveWindow : public wxWindow //private wxEvtHandler { public: - MouseMoveWindow(wxWindow* dialogToMove) : - dialogToMove_(dialogToMove) {} - - void connectSourceWindow(wxWindow* sourceWindow); + MouseMoveWindow(wxWindow& parent, + wxWindow* child1, + wxWindow* child2 = NULL, + wxWindow* child3 = NULL, + wxWindow* child4 = NULL, + wxWindow* child5 = NULL, + wxWindow* child6 = NULL); private: void LeftButtonDown(wxMouseEvent& event); - - wxWindow* dialogToMove_; }; + } diff --git a/ui/msg_popup.cpp b/ui/msg_popup.cpp index 4024a541..adf5ac7f 100644 --- a/ui/msg_popup.cpp +++ b/ui/msg_popup.cpp @@ -6,12 +6,18 @@ // #include "msg_popup.h" #include "../library/resources.h" +#include "mouse_move_dlg.h" ErrorDlg::ErrorDlg(wxWindow* parentWindow, const int activeButtons, const wxString messageText, bool& ignoreNextErrors) : ErrorDlgGenerated(parentWindow), ignoreErrors(ignoreNextErrors) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap10); //ownership passed to "this" +#endif + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("error"))); m_textCtrl8->SetValue(messageText); m_checkBoxIgnoreErrors->SetValue(ignoreNextErrors); @@ -71,6 +77,11 @@ WarningDlg::WarningDlg(wxWindow* parentWindow, int activeButtons, const wxStrin WarningDlgGenerated(parentWindow), dontShowAgain(dontShowDlgAgain) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap10); //ownership passed to "this" +#endif + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("warning"))); m_textCtrl8->SetValue(messageText); m_checkBoxDontShowAgain->SetValue(dontShowAgain); @@ -128,6 +139,11 @@ QuestionDlg::QuestionDlg(wxWindow* parentWindow, int activeButtons, const wxStri QuestionDlgGenerated(parentWindow), dontShowAgain(dontShowDlgAgain) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap10); //ownership passed to "this" +#endif + m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("question"))); m_textCtrl8->SetValue(messageText); if (dontShowAgain) diff --git a/ui/progress_indicator.cpp b/ui/progress_indicator.cpp index f41ccc36..346403ee 100644 --- a/ui/progress_indicator.cpp +++ b/ui/progress_indicator.cpp @@ -16,6 +16,7 @@ #include "../shared/global_func.h" #include "tray_icon.h" #include <boost/shared_ptr.hpp> +#include "mouse_move_dlg.h" #ifdef FFS_WIN #include "../shared/taskbar.h" @@ -512,7 +513,7 @@ SyncStatus::SyncStatusImpl::SyncStatusImpl(StatusHandler& updater, wxTopLevelWin SyncStatusDlgGenerated(parentWindow, wxID_ANY, parentWindow ? wxString(wxEmptyString) : (wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")), - wxDefaultPosition, wxSize(638, 376), + wxDefaultPosition, wxSize(638, 350), parentWindow ? wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT : //wxTAB_TRAVERSAL is needed for standard button handling: wxID_OK/wxID_CANCEL wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL), @@ -529,6 +530,11 @@ SyncStatus::SyncStatusImpl::SyncStatusImpl(StatusHandler& updater, wxTopLevelWin lastStatCallSpeed(-1000000), //some big number lastStatCallRemTime(-1000000) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmapStatus, m_staticTextStatus); //ownership passed to "this" +#endif + if (mainDialog) //save old title (will be used as progress indicator) titelTextBackup = mainDialog->GetTitle(); diff --git a/ui/search.cpp b/ui/search.cpp index 3fdb4d8b..23cf89b1 100644 --- a/ui/search.cpp +++ b/ui/search.cpp @@ -9,6 +9,7 @@ #include <wx/msgdlg.h> #include <wx/utils.h> #include <utility> +#include "mouse_move_dlg.h" class SearchDlg : public SearchDialogGenerated @@ -37,6 +38,11 @@ SearchDlg::SearchDlg(wxWindow& parentWindow, wxString& searchText, bool& respect searchText_(searchText), respectCase_(respectCase) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this); //ownership passed to "this" +#endif + m_checkBoxMatchCase->SetValue(respectCase_); m_textCtrlSearchTxt->SetValue(searchText_); diff --git a/ui/small_dlgs.cpp b/ui/small_dlgs.cpp index 785dd793..3d63db47 100644 --- a/ui/small_dlgs.cpp +++ b/ui/small_dlgs.cpp @@ -19,6 +19,7 @@ #include "../shared/build_info.h" #include <wx/wupdlock.h> #include <wx/msgdlg.h> +#include "mouse_move_dlg.h" using namespace ffs3; @@ -36,6 +37,12 @@ private: AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, + m_bitmap11); //ownership passed to "this" +#endif + m_bitmap9->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("website"))); m_bitmap10->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("email"))); m_bitmap11->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("logo"))); @@ -124,6 +131,11 @@ private: HelpDlg::HelpDlg(wxWindow* window) : HelpDlgGenerated(window) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap25, m_staticText56, m_scrolledWindow1, m_scrolledWindow5); //ownership passed to "this" +#endif + m_notebook1->SetFocus(); m_bitmap25->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("help"))); @@ -217,6 +229,11 @@ FilterDlg::FilterDlg(wxWindow* window, includeFilter(filterIncl), excludeFilter(filterExcl) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap26, m_staticTexHeader, m_bitmap8, m_bitmap9); //ownership passed to "this" +#endif + m_bitmap8->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("include"))); m_bitmap9->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("exclude"))); m_bitmap26->SetBitmap(GlobalResources::getInstance().getImageByName(wxT("filterOn"))); @@ -358,6 +375,11 @@ DeleteDialog::DeleteDialog(wxWindow* main, m_useRecycleBin(useRecycleBin), totalDelCount(totalDeleteCount) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmap12, m_staticTextHeader); //ownership passed to "this" +#endif + m_checkBoxDeleteBothSides->SetValue(deleteOnBothSides); m_checkBoxUseRecycler->SetValue(useRecycleBin); updateTexts(); @@ -471,6 +493,11 @@ CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes CustomizeColsDlgGenerated(window), output(attr) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this); //ownership passed to "this" +#endif + m_bpButton29->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("moveUp"))); m_bpButton30->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("moveDown"))); @@ -612,6 +639,11 @@ SyncPreviewDlg::SyncPreviewDlg(wxWindow* parentWindow, SyncPreviewDlgGenerated(parentWindow), m_dontShowAgain(dontShowAgain) { +#ifdef FFS_WIN + new ffs3::MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_staticTextVariant); //ownership passed to "this" +#endif + using ffs3::numberToStringSep; m_buttonStartSync->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("startSync"))); @@ -759,6 +791,11 @@ CompareCfgDialog::CompareCfgDialog(wxWindow* parentWindow, cmpVarOut(cmpVar), handleSymlinksOut(handleSymlinks) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this); //ownership passed to "this" +#endif + //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))); @@ -879,12 +916,16 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* window, xmlAccess::XmlGlobalSetti GlobalSettingsDlgGenerated(window), settings(globalSettings) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_bitmapSettings, m_staticText56); //ownership passed to "this" +#endif + 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); m_checkBoxCopyPermissions->SetValue(globalSettings.copyFilePermissions); @@ -912,7 +953,6 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* window, xmlAccess::XmlGlobalSetti void GlobalSettingsDlg::OnOkay(wxCommandEvent& event) { //write global settings only when okay-button is pressed! - settings.ignoreOneHourDiff = m_checkBoxIgnoreOneHour->GetValue(); settings.copyLockedFiles = m_checkBoxCopyLocked->GetValue(); settings.copyFilePermissions = m_checkBoxCopyPermissions->GetValue(); settings.gui.externelApplications = getExtApp(); @@ -936,7 +976,6 @@ void GlobalSettingsDlg::OnDefault(wxCommandEvent& event) { xmlAccess::XmlGlobalSettings defaultCfg; - m_checkBoxIgnoreOneHour-> SetValue(defaultCfg.ignoreOneHourDiff); m_checkBoxCopyLocked-> SetValue(defaultCfg.copyLockedFiles); m_checkBoxCopyPermissions->SetValue(defaultCfg.copyFilePermissions); set(defaultCfg.gui.externelApplications); diff --git a/ui/sorting.h b/ui/sorting.h index 94ac6f6d..305cb916 100644 --- a/ui/sorting.h +++ b/ui/sorting.h @@ -92,12 +92,12 @@ bool sortByRelativeName(const FileSystemObject& a, const FileSystemObject& b) return true; //empty rows always last const bool isDirectoryA = isDirectoryMapping(a); - const Zstring relDirNameA = isDirectoryA ? + const Zstring& relDirNameA = isDirectoryA ? a.getRelativeName<side>() : //directory a.getParentRelativeName(); //file or symlink const bool isDirectoryB = isDirectoryMapping(b); - const Zstring relDirNameB = isDirectoryB ? + const Zstring& relDirNameB = isDirectoryB ? b.getRelativeName<side>() : //directory b.getParentRelativeName(); //file or symlink diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp index c7dd58a5..c0af4881 100644 --- a/ui/sync_cfg.cpp +++ b/ui/sync_cfg.cpp @@ -7,8 +7,10 @@ #include "sync_cfg.h" #include "../library/resources.h" -#include "../shared/drag_n_drop.h" +#include "../shared/dir_name.h" #include <wx/wupdlock.h> +#include "mouse_move_dlg.h" +#include "../shared/string_conv.h" using namespace ffs3; @@ -26,10 +28,15 @@ SyncCfgDialog::SyncCfgDialog(wxWindow* window, refHandleDeletion(handleDeletion), refCustomDeletionDirectory(customDeletionDirectory), refIgnoreErrors(ignoreErrors), - dragDropCustomDelFolder(new DragDropOnDlg(m_panelCustomDeletionDir, m_dirPickerCustomDelFolder, m_textCtrlCustomDelFolder)) + customDelFolder(new DirectoryName(m_panelCustomDeletionDir, m_dirPickerCustomDelFolder, m_textCtrlCustomDelFolder)) { +#ifdef FFS_WIN + new MouseMoveWindow(*this, //allow moving main dialog by clicking (nearly) anywhere... + this, m_staticText81, m_staticText8, m_staticText101, m_staticText9); //ownership passed to "this" +#endif + setDeletionHandling(handleDeletion); - m_textCtrlCustomDelFolder->SetValue(customDeletionDirectory); + customDelFolder->setName(wxToZ(customDeletionDirectory)); //error handling if (ignoreErrors) @@ -280,7 +287,7 @@ void SyncCfgDialog::OnApply(wxCommandEvent& event) //write configuration to main dialog refSyncConfiguration = currentSyncConfig; refHandleDeletion = getDeletionHandling(); - refCustomDeletionDirectory = m_textCtrlCustomDelFolder->GetValue(); + refCustomDeletionDirectory = zToWx(customDelFolder->getName()); if (refIgnoreErrors) *refIgnoreErrors = getErrorHandling(); diff --git a/ui/sync_cfg.h b/ui/sync_cfg.h index b738111a..805bb03f 100644 --- a/ui/sync_cfg.h +++ b/ui/sync_cfg.h @@ -14,7 +14,7 @@ namespace ffs3 { -class DragDropOnDlg; +class DirectoryName; } @@ -93,7 +93,7 @@ private: wxString& refCustomDeletionDirectory; bool* refIgnoreErrors; - std::auto_ptr<ffs3::DragDropOnDlg> dragDropCustomDelFolder; + std::auto_ptr<ffs3::DirectoryName> customDelFolder; }; #endif // SYNCCONFIG_H_INCLUDED diff --git a/ui/tray_icon.cpp b/ui/tray_icon.cpp index 464bf7ef..71de676d 100644 --- a/ui/tray_icon.cpp +++ b/ui/tray_icon.cpp @@ -24,7 +24,7 @@ int roundNum(double d) //little rounding function wxIcon generateIcon(size_t percent) //generate icon with progress indicator { - percent = std::min(percent, static_cast<size_t>(100u)); //handle invalid input + percent = std::min(percent, static_cast<size_t>(100)); //handle invalid input #ifdef FFS_WIN static const wxBitmap trayIcon = GlobalResources::getInstance().getImageByName(wxT("FFS_tray_win.png")); @@ -39,25 +39,26 @@ wxIcon generateIcon(size_t percent) //generate icon with progress indicator 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()); + if ( genImage.GetWidth() > 0 && + genImage.GetHeight() > 0) + { + const int indicatorWidth = genImage.GetWidth() * .4; + const int indicatorXBegin = std::ceil((genImage.GetWidth() - indicatorWidth) / 2.0); + const int indicatorYBegin = genImage.GetHeight() - indicatorHeight; + //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[0] = 240; //red + pixelBegin[1] = 200; //green pixelBegin[2] = 0; //blue } } diff --git a/version/version.h b/version/version.h index 50c34666..5094bf93 100644 --- a/version/version.h +++ b/version/version.h @@ -2,5 +2,5 @@ namespace ffs3 { - const wxString currentVersion = wxT("3.9"); //internal linkage! + const wxString currentVersion = wxT("3.10"); //internal linkage! } diff --git a/version/version.rc b/version/version.rc index 72779244..5f56af8c 100644 --- a/version/version.rc +++ b/version/version.rc @@ -1,2 +1,2 @@ -#define VER_FREEFILESYNC 3,9,0,0 -#define VER_FREEFILESYNC_STR "3.9\0" +#define VER_FREEFILESYNC 3,10,0,0 +#define VER_FREEFILESYNC_STR "3.10\0" |