diff options
45 files changed, 3389 insertions, 1604 deletions
diff --git a/Application.cpp b/Application.cpp index 1ff7c029..ad56f9ca 100644 --- a/Application.cpp +++ b/Application.cpp @@ -45,9 +45,10 @@ bool Application::OnInit() //do not call wxApp::OnInit() to avoid using default commandline parser //set working directory to current executable directory - if (!wxSetWorkingDirectory(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath())) + const wxString workingDir = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath(); + if (!wxSetWorkingDirectory(workingDir)) { //show messagebox and quit program immediately - wxMessageBox(_("Could not set working directory to directory containing executable file!"), _("An exception occured!"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Could not set working directory:")) + wxT(" ") + workingDir, _("An exception occured!"), wxOK | wxICON_ERROR); return false; } @@ -65,7 +66,7 @@ bool Application::OnInit() //else: globalSettings already has default values } - //set program language: needs to happen aber working directory has been set! + //set program language: needs to happen after working directory has been set! SetExitOnFrameDelete(false); //prevent error messagebox from becoming top-level window programLanguage.setLanguage(globalSettings.global.programLanguage); SetExitOnFrameDelete(true); @@ -95,11 +96,11 @@ void Application::initialize() if (applicationRunsInBatchWithoutWindows) ExitMainLoop(); //exit programm on next main loop iteration - return; //program will exit automatically if a main window is present and closed + return; //program will exit automatically if a main window is present and is closed } else { - wxMessageBox(wxString(_("No valid configuration file specified: ")) + argv[1], _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("The file does not contain a valid configuration:")) + wxT(" \"") + argv[1] + wxT("\""), _("Error"), wxOK | wxICON_ERROR); return; } } @@ -170,7 +171,7 @@ public: readyToWrite = logFile.IsOpened(); if (readyToWrite) { - wxString headerLine = wxString(wxT("FreeFileSync (")) + _("Date: ") + wxDateTime::Now().FormatDate() + wxT(" ") + _("Time: ") + wxDateTime::Now().FormatTime() + wxT(")"); + wxString headerLine = wxString(wxT("FreeFileSync (")) + _("Date") + wxT(": ") + wxDateTime::Now().FormatDate() + wxT(" ") + _("Time:") + wxT(" ") + wxDateTime::Now().FormatTime() + wxT(")"); logFile.Write(headerLine + wxChar('\n')); logFile.Write(wxString().Pad(headerLine.Len(), wxChar('-')) + wxChar('\n') + wxChar('\n')); @@ -211,7 +212,7 @@ public: logFile.Write(wxChar('\n')); long time = totalTime.Time(); //retrieve total time - write(finalText + wxT(" (") + _("Total time: ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")"), _("Stop")); + write(finalText + wxT(" (") + _("Total time:") + wxT(" ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")"), _("Stop")); //logFile.close(); <- not needed } @@ -409,7 +410,7 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet batchCfg.mainCfg.syncConfiguration); if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0) { - statusUpdater.setFinalStatus(_("Nothing to synchronize. Both directories adhere to the sync-configuration!"), SyncStatus::FINISHED_WITH_SUCCESS); //inform about this special case + statusUpdater.setFinalStatus(_("Nothing to synchronize according to configuration!"), SyncStatus::FINISHED_WITH_SUCCESS); //inform about this special case returnValue = 0; return; } @@ -464,7 +465,9 @@ BatchStatusUpdater::~BatchStatusUpdater() wxString finalMessage; if (failedItems) { - finalMessage = wxString(_("Warning: Synchronization failed for ")) + globalFunctions::numberToWxString(failedItems) + _(" item(s):\n\n"); + finalMessage = wxString(_("Warning: Synchronization failed for %x item(s):")) + wxT("\n\n"); + finalMessage.Replace(wxT("%x"), globalFunctions::numberToWxString(failedItems), false); + for (unsigned int j = 0; j < failedItems; ++j) finalMessage+= unhandledErrors[j] + wxT("\n"); finalMessage+= wxT("\n"); @@ -561,7 +564,7 @@ ErrorHandler::Response BatchStatusUpdater::reportError(const wxString& text) m_log->write(text, _("Error")); if (ignoreErrors) // /|\ before return, the logfile is written!!! - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; else { abortRequested = true; @@ -573,14 +576,14 @@ ErrorHandler::Response BatchStatusUpdater::reportError(const wxString& text) if (ignoreErrors) //this option can be set from commandline or by the user in the error dialog on UI { unhandledErrors.Add(text); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } syncStatusFrame->updateStatusDialogNow(); bool ignoreNextErrors = false; - wxString errorMessage = text + wxT("\n\n") + _("Ignore this error, retry or abort synchronization?"); - ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, errorMessage, ignoreNextErrors, 90); + wxString errorMessage = text + wxT("\n\n") + _("Ignore this error, retry or abort?"); + ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, errorMessage, ignoreNextErrors); int rv = errorDlg->ShowModal(); switch (rv) @@ -588,7 +591,7 @@ ErrorHandler::Response BatchStatusUpdater::reportError(const wxString& text) case ErrorDlg::BUTTON_IGNORE: ignoreErrors = ignoreNextErrors; unhandledErrors.Add(text); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: @@ -599,7 +602,7 @@ ErrorHandler::Response BatchStatusUpdater::reportError(const wxString& text) } default: assert (false); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } } } diff --git a/Application.h b/Application.h index 42c425a7..fbb46f4b 100644 --- a/Application.h +++ b/Application.h @@ -11,7 +11,6 @@ #define FREEFILESYNCAPP_H #include <wx/app.h> -#include <wx/cmdline.h> #include "ui/smallDialogs.h" #include "library/misc.h" #include "library/processXml.h" diff --git a/Changelog.txt b/Changelog.txt index ce24ee35..ae932a36 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,23 @@ FreeFileSync ------------ +Changelog v1.14 +--------------- +Massive performance improvements: +- comprehensive analysis and optimization of comparison functionality +- new, fast directory traversing algorithm +- improved folder hierarchy compare algorithm +- lazy evaluation of formatted date strings +- new high-performance string class +=> reduction of CPU time by more than 90%! +Folder attributes are copied during synchronization +Sorting now case-insensitive (Windows-only) +Allow column positioning on main grid +Many small fixes +Added Chinese translation +Updated translation files + + Changelog v1.13 --------------- Automatically detect daylight saving time (DST) change for FAT/FAT32 drives diff --git a/FreeFileSync - Unicode.cbp b/FreeFileSync - Unicode.cbp index 7b47c0e2..1354a49e 100644 --- a/FreeFileSync - Unicode.cbp +++ b/FreeFileSync - Unicode.cbp @@ -13,6 +13,7 @@ <Option compiler="gcc" /> <Option projectLinkerOptionsRelation="2" /> <Compiler> + <Add option="-pg" /> <Add option="-g" /> <Add option="-D__WXDEBUG__" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" /> @@ -21,6 +22,7 @@ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" /> </ResourceCompiler> <Linker> + <Add option="-pg -lgmon" /> <Add library="libwxmsw28ud_adv.a" /> <Add library="libwxmsw28ud_core.a" /> <Add library="libwxbase28ud.a" /> @@ -35,7 +37,7 @@ <Option compiler="gcc" /> <Option projectLinkerOptionsRelation="2" /> <Compiler> - <Add option="-O2" /> + <Add option="-O3" /> <Add option="-DNDEBUG" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" /> </Compiler> @@ -82,8 +84,8 @@ <Add option="-D__GNUWIN32__" /> <Add option="-D__WXMSW__" /> <Add option="-DFFS_WIN" /> - <Add option="-DwxUSE_UNICODE" /> <Add option="-DTIXML_USE_STL" /> + <Add option="-DwxUSE_UNICODE" /> <Add directory="C:\Programme\C++\wxWidgets\include" /> <Add directory="C:\Programme\C++\wxWidgets\contrib\include" /> </Compiler> @@ -199,6 +201,7 @@ <Option target="Debug" /> <Option target="Release" /> </Unit> + <Unit filename="library\statusHandler.cpp" /> <Unit filename="library\statusHandler.h"> <Option target="Debug" /> <Option target="Release" /> @@ -207,6 +210,8 @@ <Unit filename="library\tinyxml\tinyxml.cpp" /> <Unit filename="library\tinyxml\tinyxmlerror.cpp" /> <Unit filename="library\tinyxml\tinyxmlparser.cpp" /> + <Unit filename="library\zstring.cpp" /> + <Unit filename="library\zstring.h" /> <Unit filename="resource.rc"> <Option compilerVar="WINDRES" /> <Option target="Debug" /> diff --git a/FreeFileSync.h b/FreeFileSync.h index 92d90189..4b269863 100644 --- a/FreeFileSync.h +++ b/FreeFileSync.h @@ -4,9 +4,8 @@ #include <wx/string.h> #include <set> #include <vector> -#include "library/statusHandler.h" #include "library/fileHandling.h" - +#include "library/zstring.h" namespace FreeFileSync { @@ -80,52 +79,31 @@ namespace FreeFileSync TYPE_FILE }; - wxString fullName; // == directory + relativeName - wxString directory; //directory to be synced + separator - wxString relativeName; //fullName without directory that is being synchronized + Zstring fullName; // == directory + relativeName + Zstring directory; //directory to be synced + separator + Zstring relativeName; //fullName without directory that is being synchronized //Note on performance: Keep redundant information "directory" and "relativeName"! //Extracting info from "fullName" instead would result in noticeable performance loss, with only limited memory reduction (note ref. counting strings)! - wxString lastWriteTime; - wxULongLong lastWriteTimeRaw; + time_t lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC wxULongLong fileSize; ObjectType objType; //is it a file or directory or initial? //the following operators are needed by template class "set" //DO NOT CHANGE THESE RELATIONS!!! -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - bool operator>(const FileDescrLine& b ) const - { - return (relativeName.CmpNoCase(b.relativeName) > 0); - } - bool operator<(const FileDescrLine& b) const - { - return (relativeName.CmpNoCase(b.relativeName) < 0); - } - bool operator==(const FileDescrLine& b) const - { - return (relativeName.CmpNoCase(b.relativeName) == 0); - } - -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case - bool operator>(const FileDescrLine& b ) const - { - return (relativeName.Cmp(b.relativeName) > 0); - } - bool operator<(const FileDescrLine& b) const - { - return (relativeName.Cmp(b.relativeName) < 0); - } - bool operator==(const FileDescrLine& b) const - { - return (relativeName.Cmp(b.relativeName) == 0); - } -#else - adapt this + bool operator < (const FileDescrLine& b) const + { //quick check based on string length: we are not interested in a lexicographical order! + const size_t aLength = relativeName.length(); + const size_t bLength = b.relativeName.length(); + if (aLength != bLength) + return aLength < bLength; +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case + return relativeName.CmpNoCase(b.relativeName) < 0; +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case + return relativeName.Cmp(b.relativeName) < 0; #endif + } }; - typedef set<FileDescrLine> DirectoryDescrType; + typedef vector<FileDescrLine> DirectoryDescrType; enum CompareFilesResult @@ -160,8 +138,8 @@ namespace FreeFileSync struct FolderPair { - wxString leftDirectory; - wxString rightDirectory; + Zstring leftDirectory; + Zstring rightDirectory; }; @@ -36,6 +36,9 @@ obj/fileHandling.o: library/fileHandling.cpp obj/multithreading.o: library/multithreading.cpp g++ $(CPPFLAGS) library/multithreading.cpp -o obj/multithreading.o +obj/statusHandler.o: library/statusHandler.cpp + g++ $(CPPFLAGS) library/statusHandler.cpp -o obj/statusHandler.o + obj/resources.o: library/resources.cpp g++ $(CPPFLAGS) library/resources.cpp -o obj/resources.o @@ -60,9 +63,11 @@ obj/tinyxmlparser.o: library/tinyxml/tinyxmlparser.cpp obj/processXml.o: library/processXml.cpp g++ $(CPPFLAGS) library/processXml.cpp -o obj/processXml.o -FreeFileSync: obj/application.o obj/algorithm.o obj/comparison.o obj/synchronization.o obj/globalFunctions.o obj/guiGenerated.o obj/mainDialog.o obj/syncDialog.o obj/customGrid.o obj/fileHandling.o obj/resources.o obj/smallDialogs.o obj/multithreading.o obj/misc.o obj/tinyxml.o obj/tinystr.o obj/tinyxmlerror.o obj/tinyxmlparser.o obj/processXml.o - g++ $(ENDFLAGS) -o FreeFileSync obj/application.o obj/algorithm.o obj/comparison.o obj/synchronization.o obj/globalFunctions.o obj/guiGenerated.o obj/mainDialog.o obj/syncDialog.o obj/customGrid.o obj/fileHandling.o obj/resources.o obj/smallDialogs.o obj/multithreading.o obj/misc.o obj/tinyxml.o obj/tinystr.o obj/tinyxmlerror.o obj/tinyxmlparser.o obj/processXml.o +obj/zstring.o: library/zstring.cpp + g++ $(CPPFLAGS) library/zstring.cpp -o obj/zstring.o + FreeFileSync: obj/application.o obj/algorithm.o obj/comparison.o obj/synchronization.o obj/globalFunctions.o obj/guiGenerated.o obj/mainDialog.o obj/syncDialog.o obj/customGrid.o obj/fileHandling.o obj/resources.o obj/smallDialogs.o obj/multithreading.o obj/statusHandler.o obj/misc.o obj/tinyxml.o obj/tinystr.o obj/tinyxmlerror.o obj/tinyxmlparser.o obj/processXml.o obj/zstring.o + g++ $(ENDFLAGS) -o FreeFileSync obj/application.o obj/algorithm.o obj/comparison.o obj/synchronization.o obj/globalFunctions.o obj/guiGenerated.o obj/mainDialog.o obj/syncDialog.o obj/customGrid.o obj/fileHandling.o obj/resources.o obj/smallDialogs.o obj/multithreading.o obj/statusHandler.o obj/misc.o obj/tinyxml.o obj/tinystr.o obj/tinyxmlerror.o obj/tinyxmlparser.o obj/processXml.o obj/zstring.o clean: find obj -type f -exec rm {} \; diff --git a/Makefile_Win_Unicode.cmd b/Makefile_Win_Unicode.cmd index aab510e1..04aa61ed 100644 --- a/Makefile_Win_Unicode.cmd +++ b/Makefile_Win_Unicode.cmd @@ -4,7 +4,7 @@ set widgetslib=C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu set sources=. set mingw=C:\Programme\C++\MinGW\bin -set parameters=-Wall -pipe -mthreads -D__GNUWIN32__ -DwxUSE_UNICODE -D__WXMSW__ -DFFS_WIN -O2 -DNDEBUG -DTIXML_USE_STL +set parameters=-Wall -pipe -mthreads -D__GNUWIN32__ -DwxUSE_UNICODE -D__WXMSW__ -DFFS_WIN -O3 -DNDEBUG -DTIXML_USE_STL path=%path%;%mingw% if not exist obj md obj mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\application.cpp -o obj\application.o @@ -13,6 +13,7 @@ mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I% mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\synchronization.cpp -o obj\synchronization.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\globalFunctions.cpp -o obj\globalFunctions.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\multithreading.cpp -o obj\multithreading.o +mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\statusHandler.cpp -o obj\statusHandler.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\fileHandling.cpp -o obj\fileHandling.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\ui\guiGenerated.cpp -o obj\GUI_Generated.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\ui\mainDialog.cpp -o obj\MainDialog.o @@ -26,7 +27,8 @@ mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I% mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\tinyxml\tinyxmlerror.cpp -o obj\tinyxmlerror.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\tinyxml\tinyxmlparser.cpp -o obj\tinyxmlparser.o mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\processXml.cpp -o obj\processXml.o +mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\zstring.cpp -o obj\zstring.o windres.exe -i %sources%\resource.rc -J rc -o obj\resource.res -O coff -I%widgets%\include -I%widgetslib% -mingw32-g++.exe -L%widgets%\lib\gcc_lib -o FreeFileSync.exe obj\application.o obj\algorithm.o obj\comparison.o obj\synchronization.o obj\globalFunctions.o obj\multithreading.o obj\fileHandling.o obj\misc.o obj\GUI_Generated.o obj\MainDialog.o obj\SyncDialog.o obj\CustomGrid.o obj\Resources.o obj\SmallDialogs.o obj\resource.res obj\tinyxml.o obj\tinystr.o obj\tinyxmlerror.o obj\tinyxmlparser.o obj\processXml.o -s -mthreads -lwxmsw28u_adv -lwxmsw28u_core -lwxbase28u -lwxpng -lwxzlib -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -lwsock32 -lodbc32 -mwindows +mingw32-g++.exe -L%widgets%\lib\gcc_lib -o FreeFileSync.exe obj\application.o obj\algorithm.o obj\comparison.o obj\synchronization.o obj\globalFunctions.o obj\multithreading.o obj\statusHandler.o obj\fileHandling.o obj\misc.o obj\GUI_Generated.o obj\MainDialog.o obj\SyncDialog.o obj\CustomGrid.o obj\Resources.o obj\SmallDialogs.o obj\resource.res obj\tinyxml.o obj\tinystr.o obj\tinyxmlerror.o obj\tinyxmlparser.o obj\processXml.o obj\zstring.o -s -mthreads -lwxmsw28u_adv -lwxmsw28u_core -lwxbase28u -lwxpng -lwxzlib -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -lwsock32 -lodbc32 -mwindows pause
\ No newline at end of file @@ -1,4 +1,4 @@ -FreeFileSync v1.13 +FreeFileSync v1.14 ------------------ Usage @@ -18,11 +18,12 @@ Key Features 7. Progress indicators are updated only every 100ms for optimal performance! 8. Subfolders are also synchronized, including empty folders. 9. Support for multiple folder pairs -10. Focus on usability: +10. Create Batch Jobs for automated synchronization via GUI. +11. Focus on usability: - Only necessary functionality on UI: no overloaded menus or icon jungle. - Select folders via drag & drop. - Last configuration and screen settings are saved automatically. - - Maintain and load different configurations by drag&drop, load-button or commandline. + - Maintain and load different configurations by drag&drop, load-button or while startup. - Double-click to show file in explorer. (Windows only) - Copy & paste support to export file-lists. - Delete superfluous/temporary files directly on main grid. @@ -30,11 +31,10 @@ Key Features - Status information and error reporting - Sort file-lists by name, size or date. - Display statistical data: total filesizes, amount of bytes that will be transfered with the current settings. -11. Easy configurable commandline mode for automated synchronization. 12. Support for filesizes > 4 GB. 13. Option to move files to Recycle Bin instead of deleting/overwriting them. 14. Automatically ignore directories "\RECYCLER" and "\System Volume Information" when comparing and sync'ing. (Windows only) -15. Localized English, German, French, Dutch and Japanese versions available. +15. Localized English, German, French, Dutch, Japanese and Chinese versions available. 16. Delete before copy: Avoid disc space shortages with large sync-operations. 17. Based on wxWidgets framework => Portable to many operating systems. 18. Filter functionality to include/exclude files from synchronization (without re-compare!). diff --git a/Resources.dat b/Resources.dat Binary files differindex 76da9870..5dcc9f95 100644 --- a/Resources.dat +++ b/Resources.dat diff --git a/algorithm.cpp b/algorithm.cpp index 4ea1a82d..e608a93b 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -6,7 +6,7 @@ #include "library/resources.h" #ifdef FFS_WIN -#include <windows.h> +#include <wx/msw/wrapwin.h> //includes "windows.h" #endif //FFS_WIN using namespace FreeFileSync; @@ -95,22 +95,23 @@ wxString FreeFileSync::formatFilesizeToShortString(const double filesize) } -wxString FreeFileSync::getFormattedDirectoryName(const wxString& dirname) +Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) { //Formatting is needed since functions in FreeFileSync.cpp expect the directory to end with '\' to be able to split the relative names. //Also improves usability. - wxString dirnameTmp = dirname; + wxString dirnameTmp = dirname.c_str(); dirnameTmp.Trim(true); //remove whitespace characters from right dirnameTmp.Trim(false); //remove whitespace characters from left if (dirnameTmp.IsEmpty()) //an empty string is interpreted as "\"; this is not desired - return wxEmptyString; + return Zstring(); //let wxWidgets do the directory formatting, e.g. replace '/' with '\' for Windows wxFileName directory = wxFileName::DirName(dirnameTmp); wxString result = directory.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); - return result; + //return Zstring(result.c_str()); + return Zstring(result); } @@ -138,7 +139,7 @@ void FreeFileSync::swapGrids(FileCompareResult& grid) } -void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler) throw(AbortThisProcess) +void FreeFileSync::adjustModificationTimes(const Zstring& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler) throw(AbortThisProcess) { #ifndef __WXDEBUG__ wxLogNull noWxLogs; //prevent wxWidgets logging @@ -147,8 +148,8 @@ void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, cons if (timeInSeconds == 0) return; - wxArrayString fileList; - wxArrayString dirList; + vector<Zstring> fileList; + vector<Zstring> dirList; while (true) //should be executed in own scope so that directory access does not disturb deletion { @@ -160,7 +161,7 @@ void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, cons catch (const FileError& e) { ErrorHandler::Response rv = errorHandler->reportError(e.show()); - if (rv == ErrorHandler::CONTINUE_NEXT) + if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop @@ -171,27 +172,27 @@ void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, cons //this part is only a bit slower than direct Windows API-access! wxDateTime modTime; - for (unsigned int j = 0; j < fileList.GetCount(); ++j) + for (unsigned int j = 0; j < fileList.size(); ++j) { while (true) //own scope for directory access to not disturb file access! { try { - wxFileName file(fileList[j]); + wxFileName file(fileList[j].c_str()); if (!file.GetTimes(NULL, &modTime, NULL)) //get modification time - throw FileError(wxString(_("Error changing modification time: ")) + wxT("\"") + fileList[j] + wxT("\"")); + throw FileError(wxString(_("Error changing modification time:")) + wxT(" \"") + fileList[j].c_str() + wxT("\"")); modTime.Add(wxTimeSpan(0, 0, timeInSeconds, 0)); if (!file.SetTimes(NULL, &modTime, NULL)) //get modification time - throw FileError(wxString(_("Error changing modification time: ")) + wxT("\"") + fileList[j] + wxT("\"")); + throw FileError(wxString(_("Error changing modification time:")) + wxT(" \"") + fileList[j].c_str() + wxT("\"")); break; } catch (const FileError& error) { ErrorHandler::Response rv = errorHandler->reportError(error.show()); - if (rv == ErrorHandler::CONTINUE_NEXT) + if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop @@ -203,18 +204,18 @@ void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, cons } -void compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter, vector<wxString>& output) +void compoundStringToTable(const Zstring& compoundInput, const defaultChar* delimiter, vector<Zstring>& output) { output.clear(); - wxString input(compoundInput); + Zstring input(compoundInput); //make sure input ends with delimiter - no problem with empty strings here if (!input.EndsWith(delimiter)) - input+= delimiter; + input += delimiter; unsigned int indexStart = 0; unsigned int indexEnd = 0; - while ((indexEnd = input.find(delimiter, indexStart )) != string::npos) + while ((indexEnd = input.find(delimiter, indexStart)) != Zstring::npos) { if (indexStart != indexEnd) //do not add empty strings { @@ -232,53 +233,23 @@ void compoundStringToTable(const wxString& compoundInput, const wxChar* delimite inline -void formatFilterString(wxString& filter) -{ -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - filter.MakeLower(); -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case -//nothing to do here -#else - adapt; -#endif -} - - -inline -void formatFilenameString(wxString& filename) -{ -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - filename.MakeLower(); -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case -//nothing to do here -#else - adapt; -#endif -} - - -inline -void mergeVectors(vector<wxString>& changing, const vector<wxString>& input) +void mergeVectors(vector<Zstring>& changing, const vector<Zstring>& input) { - for (vector<wxString>::const_iterator i = input.begin(); i != input.end(); ++i) + for (vector<Zstring>::const_iterator i = input.begin(); i != input.end(); ++i) changing.push_back(*i); } -vector<wxString> FreeFileSync::compoundStringToFilter(const wxString& filterString) +vector<Zstring> compoundStringToFilter(const Zstring& filterString) { //delimiters may be ';' or '\n' - vector<wxString> filterList; - vector<wxString> filterPreProcessing; + vector<Zstring> filterList; + vector<Zstring> filterPreProcessing; compoundStringToTable(filterString, wxT(";"), filterPreProcessing); - for (vector<wxString>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i) + for (vector<Zstring>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i) { - vector<wxString> newEntries; + vector<Zstring> newEntries; compoundStringToTable(*i, wxT("\n"), newEntries); mergeVectors(filterList, newEntries); } @@ -287,19 +258,34 @@ vector<wxString> FreeFileSync::compoundStringToFilter(const wxString& filterStri } +inline +void formatFilterString(Zstring& filter) +{ +#ifdef FFS_WIN + //Windows does NOT distinguish between upper/lower-case + filter.MakeLower(); +#elif defined FFS_LINUX + //Linux DOES distinguish between upper/lower-case +//nothing to do here +#else + adapt; +#endif +} + + void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter) { //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!! //load filter into vectors of strings //delimiters may be ';' or '\n' - vector<wxString> includeList = FreeFileSync::compoundStringToFilter(includeFilter); - vector<wxString> excludeList = FreeFileSync::compoundStringToFilter(excludeFilter); + vector<Zstring> includeList = compoundStringToFilter(includeFilter); + vector<Zstring> excludeList = compoundStringToFilter(excludeFilter); //format entries - for (vector<wxString>::iterator i = includeList.begin(); i != includeList.end(); ++i) + for (vector<Zstring>::iterator i = includeList.begin(); i != includeList.end(); ++i) formatFilterString(*i); - for (vector<wxString>::iterator i = excludeList.begin(); i != excludeList.end(); ++i) + for (vector<Zstring>::iterator i = excludeList.begin(); i != excludeList.end(); ++i) formatFilterString(*i); //############################################################## @@ -307,17 +293,17 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con //filter currentGridData for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) { - wxString filenameLeft = i->fileDescrLeft.fullName; - wxString filenameRight = i->fileDescrRight.fullName; + Zstring filenameLeft = i->fileDescrLeft.fullName; + Zstring filenameRight = i->fileDescrRight.fullName; - formatFilenameString(filenameLeft); - formatFilenameString(filenameRight); + formatFilterString(filenameLeft); + formatFilterString(filenameRight); //process include filters if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) { bool includedLeft = false; - for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) + for (vector<Zstring>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) if (filenameLeft.Matches(*j)) { includedLeft = true; @@ -334,7 +320,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) { bool includedRight = false; - for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) + for (vector<Zstring>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) if (filenameRight.Matches(*j)) { includedRight = true; @@ -352,7 +338,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) { bool excluded = false; - for (vector<wxString>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) + for (vector<Zstring>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) if (filenameLeft.Matches(*j)) { excluded = true; @@ -369,7 +355,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) { bool excluded = false; - for (vector<wxString>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) + for (vector<Zstring>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) if (filenameRight.Matches(*j)) { excluded = true; @@ -399,7 +385,7 @@ void FreeFileSync::removeFilterOnCurrentGridData(FileCompareResult& currentGridD //add(!) all files and subfolder gridlines that are dependent from the directory void FreeFileSync::addSubElements(set<int>& subElements, const FileCompareResult& grid, const FileCompareLine& relevantRow) { - wxString relevantDirectory; + Zstring relevantDirectory; if (relevantRow.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) relevantDirectory = relevantRow.fileDescrLeft.relativeName + GlobalResources::FILE_NAME_SEPARATOR; //FILE_NAME_SEPARATOR needed to exclude subfile/dirs only @@ -480,7 +466,7 @@ void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& ro //if (updateClass) -> is mandatory ErrorHandler::Response rv = errorHandler->reportError(error.show()); - if (rv == ErrorHandler::CONTINUE_NEXT) + if (rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) @@ -493,7 +479,7 @@ void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& ro } -bool FreeFileSync::sameFileTime(const wxULongLong& a, const wxULongLong& b) +bool FreeFileSync::sameFileTime(const time_t a, const time_t b) { if (a < b) return b - a <= FILE_TIME_PRECISION; @@ -501,6 +487,94 @@ bool FreeFileSync::sameFileTime(const wxULongLong& a, const wxULongLong& b) return a - b <= FILE_TIME_PRECISION; } + +inline +void writeTwoDigitNumber(unsigned int number, wxChar*& position) +{ + assert (number < 100); + + *position = '0' + number / 10; + position[1] = '0' + number % 10; + + position += 2; +} + + +inline +void writeFourDigitNumber(unsigned int number, wxChar*& position) +{ + assert (number < 10000); + + *position = '0' + number / 1000; + number %= 1000; + position[1] = '0' + number / 100; + number %= 100; + position[2] = '0' + number / 10; + number %= 10; + position[3] = '0' + number; + + position += 4; +} + + +wxString FreeFileSync::utcTimeToLocalString(const time_t utcTime) +{ +#ifdef FFS_WIN + + //convert ansi C time to FILETIME + wxULongLong fileTimeLong(utcTime); + fileTimeLong += wxULongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s + fileTimeLong *= 10000000; + + FILETIME lastWriteTimeUtc; + lastWriteTimeUtc.dwLowDateTime = fileTimeLong.GetLo(); + lastWriteTimeUtc.dwHighDateTime = fileTimeLong.GetHi(); + + FILETIME localFileTime; + if (FileTimeToLocalFileTime( //convert to local time + &lastWriteTimeUtc, //pointer to UTC file time to convert + &localFileTime //pointer to converted file time + ) == 0) + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME")); + + SYSTEMTIME time; + if (FileTimeToSystemTime( + &localFileTime, //pointer to file time to convert + &time //pointer to structure to receive system time + ) == 0) + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" FILETIME -> SYSTEMTIME")); + + //assemble time string (performance optimized) + wxChar formattedTime[21]; + wxChar* p = formattedTime; + + writeFourDigitNumber(time.wYear, p); + *(p++) = wxChar('-'); + writeTwoDigitNumber(time.wMonth, p); + *(p++) = wxChar('-'); + writeTwoDigitNumber(time.wDay, p); + *(p++) = wxChar(' '); + *(p++) = wxChar(' '); + writeTwoDigitNumber(time.wHour, p); + *(p++) = wxChar(':'); + writeTwoDigitNumber(time.wMinute, p); + *(p++) = wxChar(':'); + writeTwoDigitNumber(time.wSecond, p); + *p = 0; + + return wxString(formattedTime); + +#elif defined FFS_LINUX + tm* timeinfo; + timeinfo = localtime(&utcTime); //convert to local time + char buffer[50]; + strftime(buffer, 50, "%Y-%m-%d %H:%M:%S", timeinfo); + + return wxString(buffer); +#endif +} + + inline wxString getDriveName(const wxString& directoryName) { @@ -612,17 +686,8 @@ void FreeFileSync::checkForDSTChange(const FileCompareResult& gridData, if ( leftFile.objType == FileDescrLine::TYPE_FILE && rightFile.objType == FileDescrLine::TYPE_FILE && leftFile.fileSize == rightFile.fileSize && - -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - leftFile.directory.CmpNoCase(i->leftDirectory) == 0 && - rightFile.directory.CmpNoCase(i->rightDirectory) == 0 -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case - leftFile.directory.Cmp(i->leftDirectory) == 0 && - rightFile.directory.Cmp(i->rightDirectory) == 0 -#endif - ) + leftFile.directory.CmpNoCase(i->leftDirectory.c_str()) == 0 && //Windows does NOT distinguish between upper/lower-case + rightFile.directory.CmpNoCase(i->rightDirectory.c_str()) == 0) // { ++filesTotal; diff --git a/algorithm.h b/algorithm.h index 93d28a9e..7d20e22b 100644 --- a/algorithm.h +++ b/algorithm.h @@ -2,26 +2,39 @@ #define ALGORITHM_H_INCLUDED #include "FreeFileSync.h" +#include "library/statusHandler.h" namespace FreeFileSync { wxString formatFilesizeToShortString(const wxULongLong& filesize); wxString formatFilesizeToShortString(const double filesize); - wxString getFormattedDirectoryName(const wxString& dirname); + Zstring getFormattedDirectoryName(const Zstring& dirname); void swapGrids(FileCompareResult& grid); - void adjustModificationTimes(const wxString& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler) throw(AbortThisProcess); + void adjustModificationTimes(const Zstring& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler) throw(AbortThisProcess); void deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, ErrorHandler* errorHandler, const bool useRecycleBin) throw(AbortThisProcess); void addSubElements(set<int>& subElements, const FileCompareResult& grid, const FileCompareLine& relevantRow); void filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter); void removeFilterOnCurrentGridData(FileCompareResult& currentGridData); - vector<wxString> compoundStringToFilter(const wxString& filterString); //convert compound string, separated by ';' or '\n' into formatted vector of wxStrings - bool sameFileTime(const wxULongLong& a, const wxULongLong& b); + bool sameFileTime(const time_t a, const time_t b); + + wxString utcTimeToLocalString(const time_t utcTime); + + //enhanced binary search template: returns an iterator + template <class ForwardIterator, class T> + ForwardIterator custom_binary_search (ForwardIterator first, ForwardIterator last, const T& value) + { + first = lower_bound(first, last, value); + if (first!=last && !(value<*first)) + return first; + else + return last; + } #ifdef FFS_WIN //detect if FAT/FAT32 drive needs a +-1h time shift after daylight saving time (DST) switch due to known windows bug: diff --git a/chinese_simple.lng b/chinese_simple.lng new file mode 100644 index 00000000..198f479a --- /dev/null +++ b/chinese_simple.lng @@ -0,0 +1,520 @@ + MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI framework\n wxFormBuilder\t- wxWidgets GUI-builder\n CodeBlocks \t- Open-Source IDE + MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI framework\n wxFormBuilder\t- wxWidgets GUI-builder\n CodeBlocks \t- Open-Source IDE + Byte + Byte + GB + GB + MB + MB + PB + PB + TB + TB + kB + kB +!= files are different\n +!= 文件不同\n +&Abort +取消(&A) +&About... +关于(&A)... +&Adjust file times +调整文件时间(&A) +&Advanced +高级(&A) +&Back +返回(&B) +&Cancel +撒消(&C) +&Compare +比较(&C) +&Create +创建(&C) +&Create batch job +创建批处理作业(&C) +&Default +默认(&D) +&Export file list +导出文件列表(&E) +&File +文件(&F) +&Help +帮助(&H) +&Ignore +忽略(&I) +&Language +切换语言(&L) +&Load configuration +加载配置(&L) +&OK +确定(&O) +&Pause +暂停(&P) +&Quit +退出(&Q) +&Resolve +解决(&R) +&Retry +重试(&R) +&Start +开始(&S) +&Synchronize +同步(&S) +(-) filtered out from sync-process\n +(-) 从同步進程中过滤出\n +, +. +- different +- 不同 +- different (same date, different size) +- 不同 (日期相同,大小不同) +- equal +- 相同 +- exists left only +- 仅左侧存在的 +- exists right only +- 仅右侧存在的 +- left +- 左侧 +- left newer +- 左侧较新 +- right +- 右侧 +- right newer +- 右侧较新 +- same date (different size) +- 日期相同 (大小不同) +-Open-Source file synchronization- +-开源文件同步器- +. +, +1. &Compare +1. 比较(&C) +2. &Synchronize... +2. 同步(&S)... +2. Use wildcard characters '*' and '?'. +2. 使用通配符"*"和"?". +3. Exclude files directly on main grid via context menu. +3. 直接通过上下文菜单的主要网格排除文件. +4. Keep the number of entries small for best performance. +4. 保持小型项目的数量以获得最佳的性能. +<< left file is newer\n +<< 左侧文件较新\n +<Directory> +<目录> +<multiple selection> +<多选> +<| file on left side only\n +<| 仅左侧文件\n +== files are equal\n\n +== 文件相同\n\n +>> right file is newer\n +>> 右侧文件较新\n +Abort +取消 +Abort requested: Waiting for current operation to finish... +取消请求: 正在等待当前操作完成... +Aborted +已取消 +About +关于 +Action +动作 +Add folder pair +添加成对文件夹 +Add to exclude filter: +添加到排除过滤: +Adjust file times +调整文件时间 +Adjust modification times of all files contained in the specified folder and its subfolders. This manual adaption might become necessary if you are synchronizing against a FAT32 drive and the daylight saving time is switched. For an overview about the issue see this article: +调整修改时,所有的文件载于指定的文件夹及其子文件夹。\n这本手册适应可能需要如果您是同步对FAT32驱动器和夏令时的情况。\n概述的问题参阅此文章: +All file times have been adjusted successfully! +所有文件时间已经调整成功! +All items have been synchronized! +所有项目已经同步完成! +An exception occured! +发生异常! +Apply +应用 +As a result the files are separated into the following categories: +由该文件分为以下几类: +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: +顾名思义,这两个文件共享相同的名称被标记为相同当且仅当它们具有相同的内容。\n此选项是有用的一致性检查,而不是备份行动.因此,文件时间没有被考虑到. \n\n通过此选项使决策树较小: +Assemble a batch file with the following settings. To start synchronization in batch mode simply execute this file or schedule it in your operating system's task planner. +装配一个批处理文件使用以下设置:\n开始同步批处理模式只是执行此文件或将它计划在您的操作系统的任务规划. +Batch file created successfully! +批处理文件创建成功! +Big thanks for localizing FreeFileSync goes out to: +非常感谢做本地化FreeFileSync工作的以下人员: +Build: +开发: +Choose to hide filtered files/directories from list +从列表中选择隐藏过滤文件/文件夹 +Comma separated list +逗号分隔的列表 +Compare both sides +两侧比较 +Compare by \"File content\" +通过文件内容比较 +Compare by \"File size and date\" +通过文件大小和日期比较 +Compare by... +比较选项... +Comparing content +正在比较内容 +Comparing... +比较中... +Completed +完成 +Configuration +配置 +Configuration loaded! +配置已加载! +Configuration overview: +配置概览: +Configuration saved! +配置已保存! +Configure filter +配置过滤 +Configure filter... +设置过滤... +Configure your own synchronization rules. +配置自己的同步规则. +Confirm +确认 +Consider this when setting up synchronization rules: You might want to avoid write access to these directories so that synchronization of both does not interfere. +设置同步规则时审核:您可能要避免写入权限能存取到这些目录,以便同步时两个不干预 +Continue +继续 +Copy from left to right +从左侧复制到右侧 +Copy from left to right overwriting +从左侧复制到右侧(覆盖模式) +Copy from right to left +从右侧复制到左侧 +Copy from right to left overwriting +从右侧复制到左侧(覆盖模式) +Copy new or updated files to right folder. +复制新的或修改过的文件到右侧文件夹 +Copy to clipboard\tCTRL+C +复制到剪贴板\t使用CTRL+C键 +Could not retrieve file info for: +无法检索下列文件信息: +Create a batch job +创建一个批工作 +Create: +创建: +Current operation: +当前操作: +Custom +自定义 +DECISION TREE +决策树 +Data remaining: +剩余数据: +Data: +数据: +Date +日期 +Daylight saving time change detected for FAT/FAT32 drive. +改变时间(FAT/FAT32驱动器) +Delete files/folders existing on left side only +仅从左侧中删除文件/方件夹 +Delete files/folders existing on right side only +仅从左侧中删除文件/方件夹 +Delete files\tDEL +删除文件\t使用DEL键 +Delete: +删除: +Directories are dependent: +目录已经存在: +Directory does not exist: +目录不存在: +Do not show graphical status and error messages but write to a logfile instead +不显示图示状态和消息但写入日志 +Do not show this warning again +不再显示警告信息 +Do nothing +保持不动 +Do you really want to delete the following objects(s)? +你确定要删除下列项目吗? +Do you really want to move the following objects(s) to the recycle bin? +你确定要移到下列项目到回收站吗? +Donate with PayPal +通过PayPal捐赠 +Drag && drop +拖拽 +Email: +电子邮件: +Error +错误 +Error copying file: +复制文件出错: +Error deleting directory: +删除目录出错: +Error deleting file: +删除文件出错: +Error moving to recycle bin: +移到回收站出错: +Error parsing configuration file: +分析配置文件出错: +Error reading file: +读取文件出错: +Error traversing directory: +遍历目录出错: +Error: Source directory does not exist anymore: +错误:源目录根本不存在: +Example +例如 +Exclude +例外 +Exclude temporarily +暂时例外 +Feedback and suggestions are welcome at: +欢迎在下面提出反馈意见和建议: +File content +文件内容 +File list exported! +文件清单已经列出! +File size and date +文件大小和日期 +Filename +文件名 +Files are found equal if\n - file content\nis the same. +如果文件内容相同则认为两者相同 +Files are found equal if\n - filesize\n - last write time and date\nare the same. +如果文件大小和最后修改时间和日期相同则认为两者相同. +Files remaining: +其余档案: +Files that exist on both sides and have different content +两侧都有但内容不同的文件 +Files that exist on both sides, have same date but different filesizes +两侧都有且日期相同但文件大小不同的文件 +Files that exist on both sides, left one is newer +两侧都有但左侧较新的文件 +Files that exist on both sides, right one is newer +两侧都有但右侧较新的文件 +Files/folders remaining: +档案/文件夹剩余: +Files/folders scanned: +档案/文件夹已扫描: +Files/folders that exist on left side only +仅在左侧存在的档案/文件夹 +Files/folders that exist on right side only +仅在左侧存在的档案/文件夹 +Filter +过滤 +Filter view +过滤查看 +Folder pair +文件夹对 +FreeFileSync - Folder Comparison and Synchronization +FreeFileSync - 文件夹比较与同步 +FreeFileSync Batch Job +FreeFileSync 批处理作业 +FreeFileSync at Sourceforge +FreeFileSync at Sourceforge +FreeFileSync batch file +FreeFileSync 批处理文件 +FreeFileSync configuration +FreeFileSync 配置 +Help +帮助 +Hide files that are different +隐藏不同的档案 +Hide files that are equal +隐藏相同的档案 +Hide files that are newer on left +隐藏左侧较新的档案 +Hide files that are newer on right +隐藏右侧较新的档案 +Hide files that exist on left side only +仅隐藏在左侧的档案 +Hide files that exist on right side only +仅隐藏在右侧的档案 +Hide filtered items +隐藏已过滤的项目 +Hide further error messages during the current process +在当前進程中隐藏下一步的错误信息 +Hides error messages during synchronization:\nThey are collected and shown as a list at the end of the process +隐藏同步时的错误信息:在结束进程时收集和显示的清单 +Hints: +提示: +Homepage: +网站主页: +If you like FFS: +个人捐助: +Ignore errors +忽略错误 +Ignore next errors +忽略下一个错误 +Ignore this error, retry or abort synchronization? +忽略这个错误,重试或取消同步? +Include +包括 +Include temporarily +暂时包括 +Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* +包括:*.doc;*.zip;*.exe 除外:*\\temp\\* +Info +信息 +Information +信息 +Information: If you ignore the error or abort a re-compare will be necessary! +信息:如果你忽略或取消这个错误则有必要作再次比较! +It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) +初始化回收站是不大可能了!估计你使用的不是Windows系统.如果你想未来在此系统上应用请联系作者. :) +Left folder: +左侧方件夹: +Legend +联想 +Load configuration via...\n - this list (press DEL to delete items)\n - drag & drop to this window\n - startup parameter +加载配置(通过)...\n - 这个列表(用DEL键删除项目)\n - 拖拽到这个窗口\n - 启动参数 +Load from file... +从文件加载... +Mirror ->> +镜像 ->> +Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. +左侧文件夹镜像备份: 同步后右侧文件夹将被覆盖(完全匹配左边的文件夹). +Not all items were synchronized! Have a look at the list. +不是所有项目被同步!看一下列表 +Number of files and directories that will be created +一些文件和目录将被创建 +Number of files and directories that will be deleted +一些文件和目录将被删除 +Number of files that will be overwritten +一些文件和目录将被覆盖 +Open synchronization dialog +打开同步对话框 +Open with Explorer\tD-Click +随资源管理器打开\t使用双击D-Click +Operation aborted! +操作已取消! +Operation: +操作: +Pause +暂停 +Please fill all empty directory fields. +请填满所有空的目录区域. +Please restart synchronization! +请重新开始同步! +Press button to activate filter +请按键以激活过滤 +Preview +视图 +Published under the GNU General Public License: +在GNU通用公共许可下发布: +Quit +退出 +Relative path +相对路径 +Remove folder pair +删除文件夹对 +Result +结果 +Right folder: +右侧文件夹: +S&ave configuration +保存配置(&A) +Save current configuration to file +保存当前配置到文件 +Scanning... +正扫描... +Scanning: +扫描中: +Select a folder +选择一个文件夹 +Select variant: +选择变化的: +Set filter for synchronization +为同步设置过滤 +Show files that are different +显示不同的文件 +Show files that are equal +显示相同的文件 +Show files that are newer on left +显示左侧较新的文件 +Show files that are newer on right +显示右侧较新的文件 +Show files that exist on left side only +显示仅存在左侧的文件 +Show files that exist on right side only +显示仅存在右侧的文件 +Silent mode +静默模式 +Size +大小 +Source code written completely in C++ utilizing: +使用C++编写的源代码已完全写好: +Start +开始 +Start synchronization +开始同步 +Stop +停止 +Swap sides +换边 +Synchronization aborted! +同步已放弃! +Synchronization completed successfully. +同步成功完成. +Synchronization completed with errors! +同步已完成但有错误. +Synchronization settings +同步设置 +Synchronization status +同步状态 +Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". +同步所有的 .doc, .zip und .exe的文件( 文件夹 \"temp\"下的所有文件除外). +Synchronize both sides simultaneously: Copy new or updated files in both directions. +同时同步两侧: 复制新的或更新的文件在两个方向. +Synchronizing... +同步中... +System out of memory! +系统内在溢出! +The selected file does not exist: +选定的文件不存在: +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. Notice that the file time is allowed to deviate by up to 2 seconds. This ensures synchronization with the lower-precision file system FAT32 works correctly. +这两个同样变异评估命名文件时,在同等条件下,\n他们有同样的文件大小相同的最后收件日期和时间.\n请注意,该文件的时间允许偏差的2秒钟.\n这可确保同步较低文件系统FAT32的精密正常工作. +Time elapsed: +已用时间: +Time shift in seconds +几秒内的时间偏移 +Time: +时间: +Total amount of data that will be transferred +将被转移的总数据 +Total time: +总共时间: +Two way <-> +两侧 <-> +Unable to create logfile! +无法创建日志! +Unable to initialize Recycle Bin! +无法初始化回收站! +Unresolved errors occured during operation! +操作中出现异常错误! +Update -> +升级 -> +Update: +升级: +Use Recycle Bin +使用回收站 +Use Recycle Bin when deleting or overwriting files during synchronization +当同步时使用回收站删除或覆盖档案 +Warning +警告 +When \"Compare\" is triggered with this option set the following decision tree is processed: +当"比较" 被触发则按照决定树这个办法规定了做以下处理: +You can adjust the file times accordingly to resolve the issue: +您可以调整相应的文件时间来解决这个问题: +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +您可能会尝试再次同步,其余的项目(而不必再比较)! +different +不同 +file exists on both sides +两侧文件已存在 +on one side only +仅在一侧 +|> file on right side only\n +|> 仅在可侧的文件\n diff --git a/comparison.cpp b/comparison.cpp index 255c5b07..6ab8aa69 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -9,135 +9,20 @@ #include "algorithm.h" #ifdef FFS_WIN -#include <windows.h> +#include <wx/msw/wrapwin.h> //includes "windows.h" #endif //FFS_WIN using namespace FreeFileSync; CompareProcess::CompareProcess(bool lineBreakOnMessages, StatusHandler* handler) : - statusUpdater(handler) + statusUpdater(handler), + txtComparingContentOfFiles(_("Comparing content of files \"%x\"")) { if (lineBreakOnMessages) optionalLineBreak = wxT("\n"); } -struct FileInfo -{ - wxULongLong fileSize; //unit: bytes! - wxString lastWriteTime; - wxULongLong lastWriteTimeRaw; //unit: seconds! -}; - - -class GetAllFilesFull : public wxDirTraverser -{ -public: - GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, const wxString& optionalLineBreak, StatusHandler* updateClass = 0); - - wxDirTraverseResult OnFile(const wxString& filename); - - wxDirTraverseResult OnDir(const wxString& dirname); - - wxDirTraverseResult OnOpenError(const wxString& openerrorname); - -private: - DirectoryDescrType& m_output; - wxString directory; - int prefixLength; - FileInfo currentFileInfo; - FileDescrLine fileDescr; - const wxString m_optionalLineBreak; - StatusHandler* statusUpdater; -}; - - -inline -wxString formatTime(unsigned int number) -{ - assert (number < 100); - - if (number <= 9) - { - wxChar result[3]; - - *result = '0'; - result[1] = '0' + number; - result[2] = 0; - - return result; - } - else - { - wxString result; - if (result.Printf(wxT("%d"), number) < 0) - throw RuntimeException(_("Error when converting int to wxString")); - return result; - } -} - - -void getFileInformation(FileInfo& output, const wxString& filename) -{ -#ifdef FFS_WIN - WIN32_FIND_DATA winFileInfo; - FILETIME localFileTime; - SYSTEMTIME time; - HANDLE fileHandle; - - if ((fileHandle = FindFirstFile(filename.c_str(), &winFileInfo)) == INVALID_HANDLE_VALUE) - throw FileError(wxString(_("Could not retrieve file info for: ")) + wxT("\"") + filename + wxT("\"")); - - FindClose(fileHandle); - - if (FileTimeToLocalFileTime( - &winFileInfo.ftLastWriteTime, //pointer to UTC file time to convert - &localFileTime //pointer to converted file time - ) == 0) - throw RuntimeException(_("Error converting FILETIME to local FILETIME")); - - if (FileTimeToSystemTime( - &localFileTime, //pointer to file time to convert - &time //pointer to structure to receive system time - ) == 0) - throw RuntimeException(_("Error converting FILETIME to SYSTEMTIME")); - - output.lastWriteTime = globalFunctions::numberToWxString(time.wYear) + wxT("-") + - formatTime(time.wMonth) + wxT("-") + - formatTime(time.wDay) + wxT(" ") + - formatTime(time.wHour) + wxT(":") + - formatTime(time.wMinute) + wxT(":") + - formatTime(time.wSecond); - - //local time - output.lastWriteTimeRaw = wxULongLong(localFileTime.dwHighDateTime, localFileTime.dwLowDateTime); - - //reduce precision to 1 second (FILETIME has unit 10^-7 s) - output.lastWriteTimeRaw/= 10000000; // <- time is used for comparison only: unit switched to seconds - - output.fileSize = wxULongLong(winFileInfo.nFileSizeHigh, winFileInfo.nFileSizeLow); - -#else - struct stat fileInfo; - if (stat(filename.c_str(), &fileInfo) != 0) - throw FileError(wxString(_("Could not retrieve file info for: ")) + wxT("\"") + filename + wxT("\"")); - - tm* timeinfo; - timeinfo = localtime(&fileInfo.st_mtime); - char buffer [50]; - strftime(buffer,50,"%Y-%m-%d %H:%M:%S",timeinfo); - - //local time - output.lastWriteTime = buffer; - - //UTC time; unit: 1 second - output.lastWriteTimeRaw = fileInfo.st_mtime; - - output.fileSize = fileInfo.st_size; -#endif -} - - struct MemoryAllocator { MemoryAllocator() @@ -164,19 +49,19 @@ bool filesHaveSameContent(const wxString& filename1, const wxString& filename2) wxFFile file1(filename1.c_str(), wxT("rb")); if (!file1.IsOpened()) - throw FileError(wxString(_("Could not open file: ")) + wxT("\"") + filename1 + wxT("\"")); + throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); wxFFile file2(filename2.c_str(), wxT("rb")); - if (!file2.IsOpened()) //NO cleanup necessary for wxFFile - throw FileError(wxString(_("Could not open file: ")) + wxT("\"") + filename2 + wxT("\"")); + if (!file2.IsOpened()) //NO cleanup necessary for (wxFFile) file1 + throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); do { size_t length1 = file1.Read(memory.buffer1, memory.bufferSize); - if (file1.Error()) throw FileError(wxString(_("Error reading file: ")) + wxT("\"") + filename1 + wxT("\"")); + if (file1.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename1 + wxT("\"")); size_t length2 = file2.Read(memory.buffer2, memory.bufferSize); - if (file2.Error()) throw FileError(wxString(_("Error reading file: ")) + wxT("\"") + filename2 + wxT("\"")); + if (file2.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename2 + wxT("\"")); if (length1 != length2 || memcmp(memory.buffer1, memory.buffer2, length1) != 0) return false; @@ -256,72 +141,154 @@ void calcTotalDataForCompare(int& objectsTotal, double& dataTotal, const FileCom } -void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, const wxString& optionalLineBreak, StatusHandler* updateClass) +inline +void writeText(const wxChar* text, const int length, wxChar*& currentPos) { - assert (updateClass); + memcpy(currentPos, text, length * sizeof(wxChar)); + currentPos+=length; +} - while (true) + +class GetAllFilesFull : public FullDetailFileTraverser +{ +public: + GetAllFilesFull(DirectoryDescrType& output, Zstring dirThatIsSearched, const Zstring& optionalLineBreak, StatusHandler* updateClass) : + m_output(output), + directory(dirThatIsSearched), + m_optionalLineBreak(optionalLineBreak), + statusUpdater(updateClass) { - output.clear(); + assert(updateClass); + prefixLength = directory.length(); + textScanning = _("Scanning:"); //performance optimization + } - //get all files and folders from directory (and subdirectories) + information - GetAllFilesFull traverser(output, FreeFileSync::getFormattedDirectoryName(directory), optionalLineBreak, updateClass); - wxDir dir(directory); - if (dir.Traverse(traverser) != (size_t)-1) - break; //traversed successfully - else + virtual wxDirTraverseResult GetAllFilesFull::OnFile(const Zstring& fullFileName, const FileInfo& details) + { + FileDescrLine fileDescr; + fileDescr.fullName = fullFileName; + fileDescr.directory = directory; + fileDescr.relativeName = fullFileName.substr(prefixLength); + fileDescr.lastWriteTimeRaw = details.lastWriteTimeRaw; + fileDescr.fileSize = details.fileSize; + fileDescr.objType = FileDescrLine::TYPE_FILE; + m_output.push_back(fileDescr); + + //assemble status message (performance optimized) = textScanning + wxT(" ") + m_optionalLineBreak + wxT("\"") + fullFileName + wxT("\"") + const unsigned int statusTextMaxLen = 2000; + wxChar statusText[statusTextMaxLen]; + wxChar* position = statusText; + if (textScanning.length() + m_optionalLineBreak.length() + fullFileName.length() + 3 < statusTextMaxLen) //leave room for 0 terminating char! { - ErrorHandler::Response rv = updateClass->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + directory + wxT("\"")); - if (rv == ErrorHandler::CONTINUE_NEXT) - break; - else if (rv == ErrorHandler::RETRY) - ; //continue with loop - else - assert (false); + writeText(textScanning.c_str(), textScanning.length(), position); + writeText(wxT(" "), 1, position); + writeText(m_optionalLineBreak.c_str(), m_optionalLineBreak.length(), position); + writeText(wxT("\""), 1, position); + writeText(fullFileName.c_str(), fullFileName.length(), position); + writeText(wxT("\""), 1, position); + } + *position = 0; + + //update UI/commandline status information + statusUpdater->updateStatusText(statusText); + //add 1 element to the progress indicator + statusUpdater->updateProcessedData(1, 0); //NO performance issue at all + //trigger display refresh + statusUpdater->requestUiRefresh(); + + return wxDIR_CONTINUE; + } + + + virtual wxDirTraverseResult GetAllFilesFull::OnDir(const Zstring& fullDirName) + { +#ifdef FFS_WIN + if ( fullDirName.EndsWith(wxT("\\RECYCLER")) || + fullDirName.EndsWith(wxT("\\System Volume Information"))) + return wxDIR_IGNORE; +#endif // FFS_WIN + + FileDescrLine fileDescr; + fileDescr.fullName = fullDirName; + fileDescr.directory = directory; + fileDescr.relativeName = fullDirName.substr(prefixLength); + fileDescr.lastWriteTimeRaw = 0; //irrelevant for directories + fileDescr.fileSize = wxULongLong(0); //currently used by getBytesToTransfer + fileDescr.objType = FileDescrLine::TYPE_DIRECTORY; + m_output.push_back(fileDescr); + + //assemble status message (performance optimized) = textScanning + wxT(" ") + m_optionalLineBreak + wxT("\"") + fullDirName + wxT("\"") + const unsigned int statusTextMaxLen = 2000; + wxChar statusText[statusTextMaxLen]; + wxChar* position = statusText; + if (textScanning.length() + m_optionalLineBreak.length() + fullDirName.length() + 3 < statusTextMaxLen) //leave room for 0 terminating char! + { + writeText(textScanning.c_str(), textScanning.length(), position); + writeText(wxT(" "), 1, position); + writeText(m_optionalLineBreak.c_str(), m_optionalLineBreak.length(), position); + writeText(wxT("\""), 1, position); + writeText(fullDirName.c_str(), fullDirName.length(), position); + writeText(wxT("\""), 1, position); } + *position = 0; + + //update UI/commandline status information + statusUpdater->updateStatusText(statusText); + //add 1 element to the progress indicator + statusUpdater->updateProcessedData(1, 0); //NO performance issue at all + //trigger display refresh + statusUpdater->requestUiRefresh(); + + return wxDIR_CONTINUE; } + + + virtual wxDirTraverseResult GetAllFilesFull::OnError(const Zstring& errorText) + { + wxMessageBox(errorText, _("Error")); + return wxDIR_CONTINUE; + } + +private: + DirectoryDescrType& m_output; + Zstring directory; + int prefixLength; + const Zstring m_optionalLineBreak; + wxString textScanning; + StatusHandler* statusUpdater; +}; + + +void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, const wxString& optionalLineBreak, StatusHandler* updateClass) +{ + assert (updateClass); + + output.clear(); + + //get all files and folders from directory (and subdirectories) + information + const wxString directoryFormatted = FreeFileSync::getFormattedDirectoryName(directory); + + //GetAllFilesFull traverser(output, directoryFormatted.c_str(), optionalLineBreak.c_str(), updateClass); + GetAllFilesFull traverser(output, directoryFormatted, optionalLineBreak, updateClass); + //traverseInDetail(directoryFormatted.c_str(), &traverser); + traverseInDetail(directoryFormatted, &traverser); } struct DescrBufferLine { - wxString directoryName; + Zstring directoryName; DirectoryDescrType* directoryDesc; -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - bool operator>(const DescrBufferLine& b ) const - { - return (directoryName.CmpNoCase(b.directoryName) > 0); - } - bool operator<(const DescrBufferLine& b) const + bool operator < (const DescrBufferLine& b) const { +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case return (directoryName.CmpNoCase(b.directoryName) < 0); - } - bool operator==(const DescrBufferLine& b) const - { - return (directoryName.CmpNoCase(b.directoryName) == 0); - } - -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case - bool operator>(const DescrBufferLine& b ) const - { - return (directoryName.Cmp(b.directoryName) > 0); - } - bool operator<(const DescrBufferLine& b) const - { +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case return (directoryName.Cmp(b.directoryName) < 0); - } - bool operator==(const DescrBufferLine& b) const - { - return (directoryName.Cmp(b.directoryName) == 0); - } -#else - adapt this #endif - + } }; @@ -335,7 +302,7 @@ public: delete i->directoryDesc; } - const DirectoryDescrType* getDirectoryDescription(const wxString& directory, const wxString& optionalLineBreak, StatusHandler* statusUpdater) + DirectoryDescrType* getDirectoryDescription(const Zstring& directory, const Zstring& optionalLineBreak, StatusHandler* statusUpdater) { DescrBufferLine bufferEntry; bufferEntry.directoryName = directory; @@ -352,6 +319,8 @@ public: bufferEntry.directoryDesc = new DirectoryDescrType; buffer.insert(bufferEntry); //exception safety: insert into buffer right after creation! + bufferEntry.directoryDesc->reserve(400000); //reserve space for up to 400000 files to avoid vector reallocations + generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, optionalLineBreak, statusUpdater); //exceptions may be thrown! return bufferEntry.directoryDesc; } @@ -370,19 +339,14 @@ void CompareProcess::startCompareProcess(const vector<FolderPair>& directoryPair wxLogNull noWxLogs; //hide wxWidgets log messages in release build #endif assert (statusUpdater); - -//################################################################################################################################################ - FileCompareResult output_tmp; //write to output not before END of process! try - { - //inform about the total amount of data that will be processed from now on + { //inform about the total amount of data that will be processed from now on statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects //do basis scan: only result lines of type FILE_UNDEFINED need to be determined - performBaseComparison(directoryPairsFormatted, - output_tmp); + performBaseComparison(directoryPairsFormatted, output_tmp); if (cmpVar == CMP_BY_TIME_SIZE) { @@ -439,7 +403,9 @@ void CompareProcess::startCompareProcess(const vector<FolderPair>& directoryPair { FileCompareLine& gridline = output_tmp[*i]; - statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + optionalLineBreak + wxT("\"") + gridline.fileDescrLeft.relativeName + wxT("\"")); + wxString statusText = txtComparingContentOfFiles; + statusText.Replace(wxT("%x"), gridline.fileDescrLeft.relativeName, false); + statusUpdater->updateStatusText(statusText); //check files that exist in left and right model but have different content while (true) @@ -460,7 +426,7 @@ void CompareProcess::startCompareProcess(const vector<FolderPair>& directoryPair catch (FileError& error) { ErrorHandler::Response rv = statusUpdater->reportError(error.show()); - if (rv == ErrorHandler::CONTINUE_NEXT) + if (rv == ErrorHandler::IGNORE_ERROR) { rowsToDelete.insert(*i); break; @@ -478,9 +444,6 @@ void CompareProcess::startCompareProcess(const vector<FolderPair>& directoryPair removeRowsFromVector(output_tmp, rowsToDelete); } else assert(false); - - - statusUpdater->requestUiRefresh(); } catch (const RuntimeException& theException) { @@ -498,8 +461,7 @@ void CompareProcess::startCompareProcess(const vector<FolderPair>& directoryPair } -void CompareProcess::performBaseComparison(const vector<FolderPair>& directoryPairsFormatted, - FileCompareResult& output) +void CompareProcess::performBaseComparison(const vector<FolderPair>& directoryPairsFormatted, FileCompareResult& output) { //buffer accesses to the same directories; useful when multiple folder pairs are used DirectoryDescrBuffer descriptionBuffer; @@ -507,16 +469,25 @@ void CompareProcess::performBaseComparison(const vector<FolderPair>& directoryPa //process one folder pair after each other for (vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair) { + //PERF_START; //retrieve sets of files (with description data) - const DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, optionalLineBreak, statusUpdater); - const DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, optionalLineBreak, statusUpdater); + DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, optionalLineBreak, statusUpdater); + DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, optionalLineBreak, statusUpdater); statusUpdater->forceUiRefresh(); + //PERF_STOP; + //we use binary search when comparing the directory structures: so sort() first + sort(directoryLeft->begin(), directoryLeft->end()); + sort(directoryRight->begin(), directoryRight->end()); + //PERF_STOP; FileCompareLine newline; + //reserve some space to avoid vector reallocations + output.reserve(int(max(directoryLeft->size(), directoryRight->size()) * 1.2)); + //find files/folders that exist in left file model but not in right model for (DirectoryDescrType::iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i) - if (directoryRight->find(*i) == directoryRight->end()) + if (custom_binary_search(directoryRight->begin(), directoryRight->end(), *i) == directoryRight->end()) { newline.fileDescrLeft = *i; newline.fileDescrRight = FileDescrLine(); @@ -530,7 +501,7 @@ void CompareProcess::performBaseComparison(const vector<FolderPair>& directoryPa DirectoryDescrType::iterator i; //find files/folders that exist in right file model but not in left model - if ((i = directoryLeft->find(*j)) == directoryLeft->end()) + if ((i = custom_binary_search(directoryLeft->begin(), directoryLeft->end(), *j)) == directoryLeft->end()) { newline.fileDescrLeft = FileDescrLine(); newline.fileDescrLeft.directory = pair->leftDirectory; //directory info is needed when creating new directories @@ -574,96 +545,8 @@ void CompareProcess::performBaseComparison(const vector<FolderPair>& directoryPa else assert (false); } } + //PERF_STOP; } - statusUpdater->requestUiRefresh(); -} - - -GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, const wxString& optionalLineBreak, StatusHandler* updateClass) : - m_output(output), - directory(dirThatIsSearched), - m_optionalLineBreak(optionalLineBreak), - statusUpdater(updateClass) -{ - assert(updateClass); - prefixLength = directory.Len(); -} - - -wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename) -{ - fileDescr.fullName = filename; - fileDescr.directory = directory; - fileDescr.relativeName = filename.Mid(prefixLength); - while (true) - { - try - { - getFileInformation(currentFileInfo, filename); - break; - } - catch (FileError& error) - { - //if (updateClass) -> is mandatory - ErrorHandler::Response rv = statusUpdater->reportError(error.show()); - if ( rv == ErrorHandler::CONTINUE_NEXT) - return wxDIR_CONTINUE; - else if (rv == ErrorHandler::RETRY) - ; //continue with loop - else - assert (false); - } - } - - fileDescr.lastWriteTime = currentFileInfo.lastWriteTime; - fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw; - fileDescr.fileSize = currentFileInfo.fileSize; - fileDescr.objType = FileDescrLine::TYPE_FILE; - m_output.insert(fileDescr); - - //update UI/commandline status information - statusUpdater->updateStatusText(wxString(_("Scanning ")) + m_optionalLineBreak + wxT("\"") + filename + wxT("\"")); //NO performance issue at all - //add 1 element to the progress indicator - statusUpdater->updateProcessedData(1, 0); //NO performance issue at all - //trigger display refresh - statusUpdater->requestUiRefresh(); - - return wxDIR_CONTINUE; -} - - -wxDirTraverseResult GetAllFilesFull::OnDir(const wxString& dirname) -{ -#ifdef FFS_WIN - if ( dirname.EndsWith(wxT("\\RECYCLER")) || - dirname.EndsWith(wxT("\\System Volume Information"))) - return wxDIR_IGNORE; -#endif // FFS_WIN - - fileDescr.fullName = dirname; - fileDescr.directory = directory; - fileDescr.relativeName = dirname.Mid(prefixLength); - fileDescr.lastWriteTime = wxEmptyString; //irrelevant for directories - fileDescr.lastWriteTimeRaw = wxULongLong(0); //irrelevant for directories - fileDescr.fileSize = wxULongLong(0); //currently used by getBytesToTransfer - fileDescr.objType = FileDescrLine::TYPE_DIRECTORY; - m_output.insert(fileDescr); - - //update UI/commandline status information - statusUpdater->updateStatusText(wxString(_("Scanning ")) + m_optionalLineBreak + wxT("\"") + dirname + wxT("\"")); //NO performance issue at all - //add 1 element to the progress indicator - statusUpdater->updateProcessedData(1, 0); //NO performance issue at all - //trigger display refresh - statusUpdater->requestUiRefresh(); - - return wxDIR_CONTINUE; -} - - -wxDirTraverseResult GetAllFilesFull::OnOpenError(const wxString& openerrorname) -{ - wxMessageBox(openerrorname, _("Error")); - return wxDIR_IGNORE; } @@ -686,12 +569,12 @@ bool FreeFileSync::foldersAreValidForComparison(const vector<FolderPair>& folder //check if folder exists if (!wxDirExists(leftFolderName)) { - errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + leftFolderName + wxT("\""); + errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + leftFolderName + wxT("\""); return false; } if (!wxDirExists(rightFolderName)) { - errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + rightFolderName + wxT("\""); + errorMessage = wxString(_("Directory does not exist:")) + wxT(" \"") + rightFolderName + wxT("\""); return false; } } @@ -706,8 +589,8 @@ bool dependencyExists(const vector<wxString>& folders, const wxString& newFolder for (vector<wxString>::const_iterator i = folders.begin(); i != folders.end(); ++i) if (newFolder.StartsWith(*i) || i->StartsWith(newFolder)) { - warningMessage = wxString(_("Directories are dependent: ")) + - wxT("\"") + *i + wxT("\"") + wxT(", ") + wxT("\"") + newFolder + wxT("\""); + warningMessage = wxString(_("Directories are dependent:")) + + wxT(" \"") + *i + wxT("\"") + wxT(", ") + wxT("\"") + newFolder + wxT("\""); return true; } diff --git a/comparison.h b/comparison.h index cc80ea29..a5705238 100644 --- a/comparison.h +++ b/comparison.h @@ -2,6 +2,7 @@ #define COMPARISON_H_INCLUDED #include "FreeFileSync.h" +#include "library/statusHandler.h" namespace FreeFileSync @@ -26,6 +27,8 @@ namespace FreeFileSync StatusHandler* statusUpdater; wxString optionalLineBreak; //optional line break for status messages (used by GUI mode only) + + const Zstring txtComparingContentOfFiles; }; } @@ -10,34 +10,18 @@ PB TB TB - You may try to synchronize remaining items again (WITHOUT having to re-compare)! - U kunt proberen om de resterende bestanden opnieuw te synchroniseren (ZONDER opnieuw te hoeven vergelijken)! - already exists. Overwrite? - bestaat al. Overschrijven? - directories - paden - directory - pad - file, - Bestand, - files, - Bestanden, - item(s):\n\n - item(s):\n\n kB kB - of - van - overwriting - en overschrijven - row in view - rij in zicht - rows in view - rijen in zicht - to - naar != files are different\n != Bestanden zijn verschillend\n +%x directories +%x paden +%x files, +%x bestanden, +%x of %y rows in view +%x van de %y rijen in zicht +%x of 1 row in view +%x van 1 rij in zicht &Abort &Afbreken &About... @@ -108,12 +92,14 @@ - rechts is nieuwer - same date (different size) - zelfde datum (verschillende grootte) ----------\n ------------\n -Open-Source file synchronization- -Open-Source bestandssynchronisatie- . , +1 directory +1 pad +1 file, +1 bestand, 1. &Compare 1. &Vergelijk 1. Enter full file or directory names separated by ';' or a new line. @@ -152,8 +138,8 @@ Action Actie Add folder pair Voeg 1 paar gekoppelde mappen toe -Add to exclude filter: -Voeg toe om filter uit te sluiten: +Add to exclude filter: +Voeg toe om filter uit te sluiten: Adjust file times Pas bestandstijden aan Adjust modification times of all files contained in the specified folder and its subfolders. This manual adaption might become necessary if you are synchronizing against a FAT32 drive and the daylight saving time is switched. For an overview about the issue see this article: @@ -166,8 +152,6 @@ An exception occured! Er heeft een uitzondering plaatsgevonden! Apply Toepassen -As a result 6 different status can be returned to categorize all files: -Hierdoor kunt u 6 verschillende opties gebruiken om de bestanden te categoriseren: As a result the files are separated into the following categories: Hierdoor worden de bestanden gescheiden in de volgende categorieën: 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: @@ -178,8 +162,8 @@ Batch file created successfully! Batchbestand is succesvol aangemaakt! Big thanks for localizing FreeFileSync goes out to: Extra dank voor het vertalen van FreeFileSync gaat naar: -Build: -Gebouwd: +Build: +Gebouwd: Choose to hide filtered files/directories from list Gefilterde bestanden niet/wel weergeven Comma separated list @@ -194,8 +178,8 @@ Compare by... Vergelelijk met... Comparing content Vergelijken van inhoud -Comparing content of files -Vergelijken van bestandsinhoud +Comparing content of files \"%x\" +De inhoud van \"%x\" bestanden wordt vergeleken Comparing... Vergelijken... Completed @@ -220,6 +204,8 @@ Consider this when setting up synchronization rules: You might want to avoid wri Neem het volgende in overweging: U wilt misschien schrijfrechten op deze paden vermijden, zodat synchronisatie van bijde elkaar niet hindert. Continue Doorgaan +Conversion error: +Fout bij het converteren: Copy from left to right Kopieer van links naar rechts Copy from left to right overwriting @@ -232,28 +218,20 @@ Copy new or updated files to right folder. Kopieer nieuwe of geupdate bestanden naar de rechter map. Copy to clipboard\tCTRL+C Kopieer naar het klembord\tCTRL+C -Copying file -Bestand wordt gekopieerd -Could not open configuration file -Fout bij openen van configuratiebestand -Could not open file: -Fout bij het openen van bestand: -Could not read language file -Fout bij het lezen van taalbestand -Could not retrieve file info for: -Fout bij het verkrijgen van bestandsinformatie van: -Could not set working directory to directory containing executable file! -Fout bij het instellen van de huidige map naar een map met een toepassing erin! -Could not write configuration file -Fout bij het schrijven naar het configuratiebestand -Could not write to -Fout bij het schrijven naar +Copying file \"%x\" overwriting \"%y\" +Bestand \"%y\" wordt overschreven door een kopie van \"%x\" +Copying file \"%x\" to \"%y\" +Bestand \"%x\" wordt gekopieerd naar \"%y\" +Could not retrieve file info for: +Fout bij het verkrijgen van bestandsinformatie van: +Could not set working directory: +Kan het pad in gebruik niet instellen: Create a batch job Creëer batchjob Create: Aanmaken: -Creating folder -Folder aanmaken +Creating folder \"%x\" +Map \"%x\" wordt aangemaakt Current operation: Huidige operatie: Custom @@ -266,8 +244,6 @@ Data: Data: Date Datum -Date: -Datum: Daylight saving time change detected for FAT/FAT32 drive. Zomertijdverandering gedetecteerd voor een FAT/FAT32 schijf. Delete files/folders existing on left side only @@ -278,13 +254,13 @@ Delete files\tDEL Verwijder bestanden\tDEL Delete: Verwijderen: -Deleting file -Bestand wordt verwijderd -Deleting folder -Folder wordt verwijderd -Directories are dependent: -De volgende paden zijn afhankelijk van elkaar: -Directory does not exist: +Deleting file \"%x\" +Bestand \"%x\" wordt verwijderd +Deleting folder \"%x\" +Map \"%x\" wordt verwijderd +Directories are dependent: +De volgende paden zijn afhankelijk van elkaar: +Directory does not exist: Map bestaat niet: Do not show graphical status and error messages but write to a logfile instead Geef geen grafische status en foutmeldingen weer, maar sla het op in een logbestand @@ -306,38 +282,28 @@ Email: Email: Error Fout -Error adapting modification time of file -Er is een fout opgetreden bij het wijzigen van de modificatietijd van het bestand -Error changing modification time: -Er is een fout opgetreden bij het wijzigen van de bestandstijden -Error converting FILETIME to SYSTEMTIME -Er is een fout opgetreden bij het converteren van FILETIME naar SYSTEMTIME -Error converting FILETIME to local FILETIME -Er is een fout opgetreden bij het converteren van FILETIME naar (lokale) FILETIME -Error copying file -Er is een fout opgetreden bij het kopiëren van een bestand -Error creating directory -Er is een fout opgetreden bij het aanmaken van een pad -Error deleting directory: -Er is een fout opgetreden bij het verwijderen van een pad -Error deleting file: -Er is een fout opgetreden bij het verwijderen van een bestand -Error moving to recycle bin: -Er is een fout opgetreden bij verwijderen naar de prullenbak -Error parsing configuration file -Er is een fout opgetreden bij het aanmaken van een configuratiebestand -Error reading file: -Er is een fout opgetreden bij het lezen van het bestand: -Error traversing directory -Er is een fout opgetreden bij het doorzoeken van een map -Error when converting int to wxString -Er is een fout opgetreden bij het converteren van int naar wxString -Error when converting wxString to double -Er is een fout opgetreden bij het converteren van wxString naar double -Error when converting wxString to long -Er is een fout opgetreden bij het converteren van wxString naar long -Error: Source directory does not exist anymore: -Er is een fout opgetreden. De oorspronkelijke map bestaat niet meer: +Error changing modification time: +Er is een fout opgetreden bij het aanpassen van de bestandstijd: +Error copying file: +Er is een fout opgetreden bij het kopiëren van bestand: +Error creating directory: +Er is een fout opgetreden bij het aanmaken van pad: +Error deleting directory: +Er is een fout opgetreden bij het verwijderen van pad: +Error deleting file: +Er is een fout opgetreden bij het verwijderen van bestand: +Error moving to recycle bin: +Er is een fout opgetreden bij verwijderen naar de prullenbak: +Error parsing configuration file: +Er is een fout opgetreden bij het aanmaken van configuratiebestand: +Error reading file: +Er is een fout opgetreden bij het lezen van het bestand: +Error traversing directory: +Er is een fout opgetreden bij het doorzoeken van map: +Error writing file: +Er is een fout opgetreden bij het schrijven naar bestand: +Error: Source directory does not exist anymore: +Er is een fout opgetreden. De oorspronkelijke map bestaat niet meer: Example Voorbeeld Exclude @@ -346,6 +312,8 @@ Exclude temporarily Tijdelijk uitsluiten Feedback and suggestions are welcome at: Tips en suggesties zijn welkom op: +File already exists. Overwrite? +Het bestand bestaat al. Overschrijven? File content Bestandsinhoud File list exported! @@ -426,10 +394,10 @@ Ignore errors Negeer foutmeldingen Ignore next errors Negeer volgende foutmeldingen -Ignore this error, retry or abort comparison? -Negeer deze fout, opnieuw proberen of afbreken van deze vergelijking? Ignore this error, retry or abort synchronization? Negeer deze fout, opnieuw proberen of afbreken van deze synchronisatie? +Ignore this error, retry or abort? +Negeer deze fout, opnieuw proberen of de handeling afbreken? Include Gebruiken Include temporarily @@ -442,14 +410,14 @@ Information Informatie Information: If you ignore the error or abort a re-compare will be necessary! Informatie: als u de fout negeert of de handeling afbreekt is opnieuw vergelijken noodzakelijk! -Initialization of Recycle Bin failed! It cannot be used! -Initialiseren van de prullenbak is mislukt. Het kan niet worden gebruikt! +Initialization of Recycle Bin failed! +Initialiseren van de prullenbak is mislukt. It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) Het was niet mogelijk de prullenbak te initialiseren!\n\nHet is waarschijnlijk dat u niet Windows gebruikt.\nAls u deze optie wel wilt, neem dan alstublieft contact op met de auteur. :) Left folder: Linker map: -Legend\n -Legenda\n +Legend +Legenda Load configuration via...\n - this list (press DEL to delete items)\n - drag & drop to this window\n - startup parameter Laad configuratie via...\n - deze lijst (druk op DEL om items te verwijderen)\n - drag en drop in dit venster\n - opstartparameter Load from file... @@ -460,12 +428,10 @@ Mirror ->> Spiegelen ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Spiegel backup van de linkerkant: de rechterkant wordt overschreven en komt na synchronisatie exact overeen met de linkerkant. -No valid configuration file specified: -Er is geen geldig configuratiebestand gespecificeerd: Not all items were synchronized! Have a look at the list. Niet alle bestanden zijn gesynchroniseerd! Bekijk de lijst. -Nothing to synchronize. Both directories adhere to the sync-configuration! -Er is niks om te synchroniseren. Beide mappen komen overeen met de synchronisatie instellingen! +Nothing to synchronize according to configuration! +Volgens de gebruikte configuratie hoeft er niks gesynchroniseerd te worden! Number of files and directories that will be created Aantal mappen en bestanden die zullen worden aangemaakt Number of files and directories that will be deleted @@ -506,18 +472,16 @@ Right folder: Rechter map: S&ave configuration S&la de instellingen op +Save aborted! +Sla de afgebroken bestanden op! Save current configuration to file Sla de huidige instellingen op in een bestand -Saved aborted! -Opslaan afgebroken! -Scanning -Scannen Scanning... Data wordt doorlopen... +Scanning: +Scannen: Select a folder Selecteer een map -Select folder -Selecteer een folder Select variant: Selecteer een variant: Set filter for synchronization @@ -548,8 +512,6 @@ Stop Stop Swap sides Verwissel van kant -SyncJob.ffs_batch -SyncJob.ffs_batch Synchronization aborted! Synchronisatie afgebroken! Synchronization completed successfully. @@ -568,10 +530,10 @@ Synchronizing... Aan het synchroniseren... System out of memory! Systeem heeft te weinig geheugen -The selected file does not contain a valid configuration! -Het geselecteerde bestand bevat geen geldige configuratie! -The selected file does not exist: -Het volgende geselecteerde bestand bestaat niet: +The file does not contain a valid configuration: +Het bestand bevat geen geldige configuratie: +The selected file does not exist: +Het volgende geselecteerde bestand bestaat niet: 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. Notice that the file time is allowed to deviate by up to 2 seconds. This ensures synchronization with the lower-precision file system FAT32 works correctly. Deze variant ziet twee gelijknamige bestanden als gelijk wanneer ze dezelfde bestandsgrootte EN tijdstempel hebben. Merk op dat tijdstempel 2 seconden mag verschillen. Dit zorgt ervoor dat het minder nauwkeurige FAT-32 ook kan worden gesynchroniseerd. Time elapsed: @@ -580,12 +542,12 @@ Time shift in seconds Timeshift in seconden Time shift: Timeshift: -Time: -Tijd: +Time: +Tijd: Total amount of data that will be transferred Hoeveelheid data die verplaatst word -Total time: -Totale tijd: +Total time: +Totale tijd: Two way <-> Beide zijden <-> Unable to create logfile! @@ -604,12 +566,14 @@ Use Recycle Bin when deleting or overwriting files during synchronization Gebruik de prullenbak wanneer bestanden worden verwijderd of overschreven tijdens het synchroniseren Warning Attentie -Warning: Synchronization failed for -Attentie: synchronisatie mislukt voor +Warning: Synchronization failed for %x item(s): +Let op: %x item(s) konden niet worden gesynchroniseerd: When \"Compare\" is triggered with this option set the following decision tree is processed: Wanneer \"Compare\" met deze instelling aan wordt gebruikt zal de volgende beslissingsboom gebruikt worden: You can adjust the file times accordingly to resolve the issue: U kunt de bestandstijden aanpassen om het probleem op te lossen: +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +U kunt proberen om de resterende bestanden opnieuw te synchroniseren (ZONDER opnieuw te hoeven vergelijken)! different verschillend file exists on both sides @@ -10,34 +10,18 @@ Po TB To - You may try to synchronize remaining items again (WITHOUT having to re-compare)! - Vous pouvez essayer de synchroniser à nouveau les éléments restants (SANS avoir à les re-comparer) ! - already exists. Overwrite? - existe déjà. Voulez-vous le remplacer ? - directories - répertoires - directory - répertoire - file, - fichier, - files, - fichiers, - item(s):\n\n - Elément(s):\n\n kB ko - of - sur - overwriting - remplacement - row in view - ligne sur la vue - rows in view - lignes sur la vue - to - vers != files are different\n != les fichiers sont différents\n +%x directories +%x dossiers +%x files, +%x fichiers, +%x of %y rows in view +%x sur %y lignes affichées +%x of 1 row in view +%x sur 1 ligne affichée &Abort &Abandon &About... @@ -47,7 +31,7 @@ &Advanced &Avancé &Back -&Retour +&Quitter &Cancel &Annuler &Compare @@ -87,7 +71,7 @@ (-) filtered out from sync-process\n (-) non synchronisés\n , -. + - different - fichiers différents - different (same date, different size) @@ -108,16 +92,18 @@ - fichier de droite plus récent - same date (different size) - même date (taille différente) ----------\n ------------\n -Open-Source file synchronization- -Synchronisation de fichiers Open-Source- . , +1 directory +1 dossier +1 file, +1 fichier, 1. &Compare 1. &Comparer 1. Enter full file or directory names separated by ';' or a new line. -1. Entrez le nom complet des fichiers ou des dossier séparés par un ';' ou par un 'retour charit'. +1. Entrez le nom complet des fichiers ou des dossier séparés par un ';' ou par un 'retour chariot'. 2. &Synchronize... 2. &Synchroniser... 2. Use wildcard characters '*' and '?'. @@ -152,8 +138,8 @@ Action Action Add folder pair Ajout d'un couple de dossiers -Add to exclude filter: -Ajout au filtre exclure: +Add to exclude filter: +Ajout au filtre exclure: Adjust file times Ajuster les dates de fichiers Adjust modification times of all files contained in the specified folder and its subfolders. This manual adaption might become necessary if you are synchronizing against a FAT32 drive and the daylight saving time is switched. For an overview about the issue see this article: @@ -166,8 +152,6 @@ An exception occured! Une violation s'est produite! Apply Apliquer -As a result 6 different status can be returned to categorize all files: -En conclusion, 6 états différents caractérisent tous les fichiers: As a result the files are separated into the following categories: En conclusion, les fichiers sont répartis dans les catégories suivantes: 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: @@ -178,8 +162,8 @@ Batch file created successfully! Fichier de commandes créé avec succès! Big thanks for localizing FreeFileSync goes out to: Pour les traductions de FreeFileSync, un grand merci à: -Build: -Créé: +Build: +Créé: Choose to hide filtered files/directories from list Masquer les fichiers/répertoires filtrés Comma separated list @@ -194,8 +178,8 @@ Compare by... Comparaison par... Comparing content Comparaison du contenu -Comparing content of files -Comparaison du contenu des fichiers en cours +Comparing content of files \"%x\" +comparaison du contenu des fichiers \"%x\" Comparing... Comparaison en cours... Completed @@ -220,6 +204,8 @@ Consider this when setting up synchronization rules: You might want to avoid wri Lisez ceci lors de la mise à jour des règles de synchronisation : Vous voudrez peut-être éviter l'accès en écriture à ces répertoires pour que la synchronisation n'interfère pas. Continue Continuer +Conversion error: +Erreur de conversion: Copy from left to right Copie de gauche à droite Copy from left to right overwriting @@ -229,31 +215,23 @@ Copie de droite à gauche Copy from right to left overwriting Copie de droite à gauche avec remplacement Copy new or updated files to right folder. -Copie defichiers nouveaux ou modifiés dans le dossier de droite. +Copie de fichiers nouveaux ou modifiés dans le dossier de droite. Copy to clipboard\tCTRL+C Copier dans le presse-papiers\tCTRL+C -Copying file -Copie du fichier en cours -Could not open configuration file -Ipossible d'ouvrir le fichier de configuration -Could not open file: -Erreur lors de l'ouverture de : -Could not read language file -Impossible de lire le fichier de langue -Could not retrieve file info for: -Erreur lors de la lecture des attributs de fichier de : -Could not set working directory to directory containing executable file! -Impossible de définir le répertoire de travail à partir du répertoire contenant le fichier exécutable! -Could not write configuration file -Impossible d'écrire le fichier de configuration -Could not write to -Erreur en écriture sur +Copying file \"%x\" overwriting \"%y\" +Copie fichier \"%x\" écrasant \"%y\" +Copying file \"%x\" to \"%y\" +Copie fichier \"%x\" vers \"%y\" +Could not retrieve file info for: +Erreur lors de la lecture des attributs de fichier de : +Could not set working directory: +Impossible de définir le répertoire de travail: Create a batch job Création du fichier de commandes Create: Créations: -Creating folder -Création d'un répertoire +Creating folder \"%x\" +Création du dossier \"%x\" Current operation: Opération en cours: Custom @@ -266,8 +244,6 @@ Data: Données: Date Date -Date: -Date: Daylight saving time change detected for FAT/FAT32 drive. Changement Heure d'été détecté sur un lecteur FAT/FAT32. Delete files/folders existing on left side only @@ -278,14 +254,14 @@ Delete files\tDEL Suppression des fichiers\tDEL Delete: Suppressions: -Deleting file -Suppression du fichier -Deleting folder -Suppression du répertoire -Directories are dependent: -Les dossiers sont liés: -Directory does not exist: -Le répertoire n'existe pas: +Deleting file \"%x\" +Suppression du fichier \"%x\" +Deleting folder \"%x\" +Suppression du dossier \"%x\" +Directories are dependent: +Les dossiers sont liés: +Directory does not exist: +Le répertoire n'existe pas: Do not show graphical status and error messages but write to a logfile instead Ne pas afficher l'état graphique ni les messages mais les écrire sur un fichier log Do not show this warning again @@ -306,38 +282,28 @@ Email: Email: Error Erreur -Error adapting modification time of file -Erreur lors de la modification de la date du fichier -Error changing modification time: -Erreur lors du changement de la date de modification: -Error converting FILETIME to SYSTEMTIME -Erreur lors de la conversion de FILETIME en SYSTEMTIME -Error converting FILETIME to local FILETIME -Erreur lors de la conversion de FILETIME en FILETIME local -Error copying file -Erreur lors de la copie du fichier -Error creating directory -Erreur lors de la création du répertoire -Error deleting directory: -Erreur lors de la suppression d'un répertoire: -Error deleting file: -Erreur lors de la suppression d'un fichier: -Error moving to recycle bin: -Erreur lors du déplacement vers la corbeille: -Error parsing configuration file -Erreur lors de l'analyse du fichier de configuration -Error reading file: -Erreur lors de la lecture du fichier: -Error traversing directory -Erreur lors du parcours du répertoire -Error when converting int to wxString -Erreur de conversion (int en wxString) -Error when converting wxString to double -Erreur de conversion (wxString en double) -Error when converting wxString to long -Erreur de conversion (wxString en long) -Error: Source directory does not exist anymore: -Erreur: le répertoire source n'existe plus: +Error changing modification time: +Erreur lors du changement de la date de modification: +Error copying file: +Erreur lors de la copie du fichier: +Error creating directory: +Erreur lors de la création d'un répertoire: +Error deleting directory: +Erreur lors de la suppression d'un répertoire: +Error deleting file: +Erreur lors de la suppression d'un fichier: +Error moving to recycle bin: +Erreur lors du déplacement vers la corbeille: +Error parsing configuration file: +Erreur lors de l'analyse du fichier de configuration: +Error reading file: +Erreur lors de la lecture du fichier: +Error traversing directory: +Erreur lors du parcours du répertoire: +Error writing file: +Erreur lors de l'écriture du fichier: +Error: Source directory does not exist anymore: +Erreur: le répertoire source n'existe plus: Example Exemple Exclude @@ -346,6 +312,8 @@ Exclude temporarily Exclure temporairement Feedback and suggestions are welcome at: Commentaires et suggestions sont les bienvenus à: +File already exists. Overwrite? +Le fichier existe déjà. Voulez-vous le remplacer? File content Contenu du fichier File list exported! @@ -426,10 +394,10 @@ Ignore errors Ignorer les erreurs Ignore next errors Ignorer les erreurs suivantes -Ignore this error, retry or abort comparison? -Ignorer l'erreur, réessayer ou abandonner la comparaison ? Ignore this error, retry or abort synchronization? Ignorer l'erreur, réessayer ou abandonner la synchronisation ? +Ignore this error, retry or abort? +Ignorer l'erreur, réessayer ou abandonner? Include Inclure Include temporarily @@ -442,14 +410,14 @@ Information Information Information: If you ignore the error or abort a re-compare will be necessary! Information: Si vous ignorez l'erreur ou abandonnez, il sera nécessaire de relancer la comparaison! -Initialization of Recycle Bin failed! It cannot be used! -Erreur lors de l'initialisation de la corbeille ! La corbeille ne peut être utilisée! +Initialization of Recycle Bin failed! +Erreur lors de l'initialisation de la corbeille ! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) Impossible d'accéder à la corbeille!\n\nIl est probable que vous n'utilisez pas Windows.\nSi vous désirez utilisee cette fonctionnalité, veuillez contacter l'auteur. :) Left folder: Répertoire de gauche: -Legend\n -Legende\n +Legend +Legende Load configuration via...\n - this list (press DEL to delete items)\n - drag & drop to this window\n - startup parameter Charger la configuration via...\n - cette liste (Appuyez sur Suppr pour supprimer des éléments),\n - un glisser-déposer vers cette fenêtre,\n - les paramètres de démarrage. Load from file... @@ -460,12 +428,10 @@ Mirror ->> Mirroir ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Sauvegarde miroir du répertoire de gauche : Le répertoire de droite sera écrasé et exactement identique au répertoire de gauche après la synchronisation. -No valid configuration file specified: -Auncun fichier de configuration valide spécifié: Not all items were synchronized! Have a look at the list. Tous les éléments n'ont pas été synchronisés! Veuillez vérifier la liste. -Nothing to synchronize. Both directories adhere to the sync-configuration! -Rien à synchroniser. Les deux répertoires sont conformes aux paramètres de synchronisation! +Nothing to synchronize according to configuration! +Rien à synchroniser dans cette configuration! Number of files and directories that will be created Nombre de fichiers et de répertoires qui seront créés Number of files and directories that will be deleted @@ -501,23 +467,21 @@ Chemin Remove folder pair Supprimer le couple de dossiers Result -Résultat +Situation Right folder: Répertoire de droite: S&ave configuration -S&auvegarder le configuration. +S&auvegarder la configuration +Save aborted! +Sauvegarde abandonnée! Save current configuration to file Enregistrer la configuration courante -Saved aborted! -Enregistrement annulé! -Scanning -Lecture en cours Scanning... Lecture en cours... +Scanning: +Lecture en cours: Select a folder Choisissez un répertoire -Select folder -Choisissez un répertoire Select variant: Choisissez une variante: Set filter for synchronization @@ -548,8 +512,6 @@ Stop Stop Swap sides Permuter les côtés -SyncJob.ffs_batch -SyncJob.ffs_batch Synchronization aborted! Synchronisation abandonnée! Synchronization completed successfully. @@ -568,10 +530,10 @@ Synchronizing... Synchronisation en cours... System out of memory! Erreur mémoire système! -The selected file does not contain a valid configuration! -Le fichier sélectionné ne contient pas de configuration valide! -The selected file does not exist: -Le fichier sélectionné n'existe pas: +The file does not contain a valid configuration: +Le fichier ne contient pas de configuration valide +The selected file does not exist: +Le fichier sélectionné n'existe pas: 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. Notice that the file time is allowed to deviate by up to 2 seconds. This ensures synchronization with the lower-precision file system FAT32 works correctly. Cette variante définit comme identiques deux fichiers de même nom lorsqu'ils ont la même taille et le même date et heure de modification. Attention : la précision de l'heure est mesurée à 2 secondes près. Cela permet d'assurer la synchronisation avec la précision du systéme de fichiers FAT32. Time elapsed: @@ -580,12 +542,12 @@ Time shift in seconds Décalage horaire en secondes Time shift: Décalage horaire: -Time: -Heure: +Time: +Heure: Total amount of data that will be transferred Volume de données à transférer -Total time: -Temps total: +Total time: +Temps total: Two way <-> Des 2 côtés <-> Unable to create logfile! @@ -604,12 +566,14 @@ Use Recycle Bin when deleting or overwriting files during synchronization Utilisation de la corbeille lors de la suppression ou du remplacement des fichiers pendant la synchronisation Warning Attention -Warning: Synchronization failed for -Attention : la synchronisation a échoué à cause de +Warning: Synchronization failed for %x item(s): +Attention: La synchronisation a échouée pour %x élément(s): When \"Compare\" is triggered with this option set the following decision tree is processed: Quand \"Compare\" est lancé avec cette option, l'arbre de décision suivant est éxécuté: You can adjust the file times accordingly to resolve the issue: Vous pouvez modifier l'heure des fichiers pour résoudre le problème: +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +Vous pouvez essayer de synchroniser à nouveau les éléments restants (SANS avoir à les re-comparer) ! different fichiers différents file exists on both sides @@ -10,34 +10,18 @@ PB TB TB - You may try to synchronize remaining items again (WITHOUT having to re-compare)! - Verbliebene Elemente können nochmals synchronisiert werden (OHNE dass ein erneuter Vergleich notwendig ist)! - already exists. Overwrite? - existiert bereits. Überschreiben? - directories - Verzeichnisse - directory - Verzeichnis - file, - Datei, - files, - Dateien, - item(s):\n\n - Element(e):\n\n kB kB - of - von - overwriting - und überschreibe - row in view - Zeile zur Ansicht - rows in view - Zeilen zur Ansicht - to - nach != files are different\n != Dateien sind verschieden\n +%x directories +%x Verzeichnisse +%x files, +%x Dateien, +%x of %y rows in view +%x von %y Zeilen zur Ansicht +%x of 1 row in view +%x von 1 Zeile zur Ansicht &Abort &Abbruch &About... @@ -108,12 +92,14 @@ E&xportiere Dateiliste - rechts neuer - same date (different size) - gleiches Datum (unterschiedliche Größe) ----------\n ------------\n -Open-Source file synchronization- -Open-Source Datei-Synchronisation- . , +1 directory +1 Verzeichnis +1 file, +1 Datei, 1. &Compare 1. &Vergleichen 1. Enter full file or directory names separated by ';' or a new line. @@ -152,8 +138,8 @@ Action Aktion Add folder pair Verzeichnispaar hinzufügen -Add to exclude filter: -Über Filter ausschließen: +Add to exclude filter: +Über Filter ausschließen: Adjust file times Dateizeiten ändern Adjust modification times of all files contained in the specified folder and its subfolders. This manual adaption might become necessary if you are synchronizing against a FAT32 drive and the daylight saving time is switched. For an overview about the issue see this article: @@ -166,8 +152,6 @@ An exception occured! Eine Ausnahme ist aufgetreten! Apply Anwenden -As a result 6 different status can be returned to categorize all files: -Als Ergebnis werden 6 verschiedene Status zurückgegeben, um Dateien zu kategorisieren: As a result the files are separated into the following categories: Das Ergebnis ist eine Aufteilung in folgende Kategorien: 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: @@ -178,8 +162,8 @@ Batch file created successfully! Batch-Datei wurde erfolgreich erstellt! Big thanks for localizing FreeFileSync goes out to: Vielen Dank für die Lokalisation von FreeFileSync an: -Build: -Build: +Build: +Build: Choose to hide filtered files/directories from list Gefilterte Dateien ein-/ausblenden Comma separated list @@ -194,8 +178,8 @@ Compare by... Vergleichen nach... Comparing content Vergleiche Dateiinhalt -Comparing content of files -Vergleiche Inhalt der Dateien +Comparing content of files \"%x\" +Vergleiche Inhalt der Dateien \"%x\" Comparing... Vergleiche... Completed @@ -220,6 +204,8 @@ Consider this when setting up synchronization rules: You might want to avoid wri Achtung beim Festlegen der Synchronisationseinstellungen: Ein Schreibzugriff auf diese Verzeichnisse sollte vermieden werden, so dass sich die Synchronization von beiden nicht gegenseitig beeinflusst. Continue Fortfahren +Conversion error: +Fehler bei Konvertierung: Copy from left to right Von links nach rechts kopieren Copy from left to right overwriting @@ -232,28 +218,20 @@ Copy new or updated files to right folder. Kopiere neue oder aktualisierte Dateien in den rechten Ordner. Copy to clipboard\tCTRL+C Kopiere in Zwischenablage\tCTRL+C -Copying file -Kopiere Datei -Could not open configuration file -Fehler beim Öffnen der Datei -Could not open file: -Fehler beim Öffnen der Datei: -Could not read language file -Fehler beim Lesen der Sprachdatei -Could not retrieve file info for: -Fehler beim Lesen der Dateiattribute von: -Could not set working directory to directory containing executable file! -Arbeitsverzeichnisses konnte nicht auf Pfad der .exe-Datei gelegt werden! -Could not write configuration file -Fehler beim Schreiben der Konfigurationsdatei -Could not write to -Fehler beim Schreiben von +Copying file \"%x\" overwriting \"%y\" +Kopiere Datei \"%x\" und überschreibe \"%y\" +Copying file \"%x\" to \"%y\" +Kopiere Datei \"%x\" nach \"%y\" +Could not retrieve file info for: +Fehler beim Lesen der Dateiattribute von: +Could not set working directory: +Fehler beim Setzen des Arbeitsverzeichnisses: Create a batch job Erstelle Batch-Job Create: Erstellen: -Creating folder -Erstelle Verzeichnis +Creating folder \"%x\" +Erstelle Verzeichnis \"%x\" Current operation: Aktuelle Operation: Custom @@ -266,8 +244,6 @@ Data: Daten: Date Datum -Date: -Datum: Daylight saving time change detected for FAT/FAT32 drive. Sommer-/Winterzeitumstellung wurde für ein FAT/FAT32 Laufwerk erkannt. Delete files/folders existing on left side only @@ -278,14 +254,14 @@ Delete files\tDEL Lösche Dateien\tDEL Delete: Löschen: -Deleting file -Lösche Datei -Deleting folder -Lösche Verzeichnis -Directories are dependent: -Die Verzeichnisse sind voneinander abhängig: -Directory does not exist: -Das Verzeichnis existiert nicht: +Deleting file \"%x\" +Lösche Datei \"%x\" +Deleting folder \"%x\" +Lösche Verzeichnis \"%x\" +Directories are dependent: +Die Verzeichnisse sind voneinander abhängig: +Directory does not exist: +Das Verzeichnis existiert nicht: Do not show graphical status and error messages but write to a logfile instead Keine graphischen Status- und Fehlermeldungen anzeigen, sondern eine Logdatei erstellen Do not show this warning again @@ -306,38 +282,28 @@ Email: Email: Error Fehler -Error adapting modification time of file -Fehler beim Anpassen des Datums der letzten Änderung der Datei -Error changing modification time: -Fehler beim Setzen der Änderungszeit: -Error converting FILETIME to SYSTEMTIME -Fehler beim Konvertieren der FILETIME nach SYSTEMTIME -Error converting FILETIME to local FILETIME -Fehler beim Konvertieren der FILETIME nach (lokale) FILETIME -Error copying file -Fehler beim Kopieren der Datei -Error creating directory -Fehler beim Erstellen des Verzeichnisses -Error deleting directory: -Fehler beim Löschen des Verzeichnisses: -Error deleting file: -Fehler beim Löschen der Datei: -Error moving to recycle bin: -Fehler beim Verschieben in den Papierkorb: -Error parsing configuration file -Fehler beim Auswerten der Konfigurationsdatei -Error reading file: -Fehler beim Lesen der Datei: -Error traversing directory -Fehler beim Durchsuchen des Verzeichnisses -Error when converting int to wxString -Fehler bei Konvertierung (int nach wxString) -Error when converting wxString to double -Fehler bei Konvertierung (wxString nach double) -Error when converting wxString to long -Fehler bei Konvertierung (wxString nach long) -Error: Source directory does not exist anymore: -Fehler: Quellverzeichnis existiert nicht mehr: +Error changing modification time: +Fehler beim Setzen der Dateiänderungszeit: +Error copying file: +Fehler beim Kopieren der Datei: +Error creating directory: +Fehler beim Erstellen des Verzeichnisses: +Error deleting directory: +Fehler beim Löschen des Verzeichnisses: +Error deleting file: +Fehler beim Löschen der Datei: +Error moving to recycle bin: +Fehler beim Verschieben in den Papierkorb: +Error parsing configuration file: +Fehler beim Auswerten der Konfigurationsdatei: +Error reading file: +Fehler beim Lesen der Datei: +Error traversing directory: +Fehler beim Durchsuchen des Verzeichnisses: +Error writing file: +Fehler beim Schreiben der Datei: +Error: Source directory does not exist anymore: +Fehler: Quellverzeichnis existiert nicht mehr: Example Beispiel Exclude @@ -346,6 +312,8 @@ Exclude temporarily Temporär ausschließen Feedback and suggestions are welcome at: Feedback und Vorschläge sind willkommen unter: +File already exists. Overwrite? +Die Datei existiert bereits. Überschreiben? File content Dateiinhalt File list exported! @@ -426,10 +394,10 @@ Ignore errors Fehler ignorieren Ignore next errors Weitere Fehler ignorieren -Ignore this error, retry or abort comparison? -Fehler ignorieren, wiederholen oder Vergleich abbrechen? Ignore this error, retry or abort synchronization? Fehler ignorieren, wiederholen oder Synchronisation abbrechen? +Ignore this error, retry or abort? +Fehler ignorieren, wiederholen oder abbrechen? Include Einschließen Include temporarily @@ -442,14 +410,14 @@ Information Information Information: If you ignore the error or abort a re-compare will be necessary! Information: Wenn der Fehler nicht behoben wird, muss der Vergleich erneut gestartet werden! -Initialization of Recycle Bin failed! It cannot be used! -Die Initialisierung des Papierkorbs ist fehlgeschlagen! Er kann nicht verwendet werden! +Initialization of Recycle Bin failed! +Die Initialisierung des Papierkorbs ist fehlgeschlagen! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) Die Papierkorbfunktion steht nicht zur Verfügung!\n\nWahrscheinlich ist das aktuelle Betriebssystem nicht Windows.\nWenn Sie diese Funktion wirklich benötigen, kontaktieren Sie bitte den Autor. :) Left folder: Linker Ordner: -Legend\n -Legende\n +Legend +Legende Load configuration via...\n - this list (press DEL to delete items)\n - drag & drop to this window\n - startup parameter Lade Konfiguration über...\n - diese Liste (DEL-Taste löscht Einträge)\n - Drag & Drop auf dieses Fenster\n - Startupparameter Load from file... @@ -460,12 +428,10 @@ Mirror ->> Spiegel ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Spiegel-Backup des linken Ordners erstellen: Der rechte Ordner wird dabei überschrieben und nach der Synchronisation dem linken exakt gleichen. -No valid configuration file specified: -Keine gültige Konfigurationsdatei angegeben: Not all items were synchronized! Have a look at the list. Nicht alle Objekte wurden synchronisiert! Siehe die verbliebenen Elemente im Hauptfenster. -Nothing to synchronize. Both directories adhere to the sync-configuration! -Nichts zu synchronisieren. Beide Verzeichnisse entsprechen den Synchronisationseinstellungen! +Nothing to synchronize according to configuration! +Es gibt nichts zu synchronisieren gemäß aktueller Einstellungen! Number of files and directories that will be created Anzahl der Dateien und Verzeichnisse, die erstellt werden Number of files and directories that will be deleted @@ -506,18 +472,16 @@ Right folder: Rechter Ordner: S&ave configuration S&peichere Konfiguration +Save aborted! +Speicherung abgebrochen! Save current configuration to file Aktuelle Konfiguration in Datei sichern -Saved aborted! -Speichern abgebrochen! -Scanning -Lese Datei Scanning... Suche Dateien... +Scanning: +Lese Datei: Select a folder Verzeichnis wählen -Select folder -Verzeichnis auswählen Select variant: Variante auswählen: Set filter for synchronization @@ -548,8 +512,6 @@ Stop Stop Swap sides Vertausche Seiten -SyncJob.ffs_batch -SyncJob.ffs_batch Synchronization aborted! Synchronisation abgebrochen! Synchronization completed successfully. @@ -568,10 +530,10 @@ Synchronizing... Synchronisiere... System out of memory! Zu wenig freier Arbeitsspeicher! -The selected file does not contain a valid configuration! -Die ausgewählte Datei enthält keine gültige Konfiguration! -The selected file does not exist: -Die ausgewählte Datei existiert nicht: +The file does not contain a valid configuration: +Die Datei enthält keine gültige Konfiguration: +The selected file does not exist: +Die ausgewählte Datei existiert nicht: 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. Notice that the file time is allowed to deviate by up to 2 seconds. This ensures synchronization with the lower-precision file system FAT32 works correctly. Diese Variante identifiziert zwei gleichnamige Dateien als gleich, wenn sie die gleiche Dateigröße haben UND der Zeitpunkt der letzten Änderung derselbe ist. Dabei wird eine Abweichung von bis zu zwei Sekunden toleriert. So ist sichergestellt, dass eine Synchronisation gegen ein FAT32 Dateisystem korrekt funktioniert. Time elapsed: @@ -580,12 +542,12 @@ Time shift in seconds Zeitverschiebung in Sekunden Time shift: Zeitverschiebung: -Time: -Zeit: +Time: +Zeit: Total amount of data that will be transferred Gesamtmenge der Daten, die übertragen werden -Total time: -Gesamtzeit: +Total time: +Gesamtzeit: Two way <-> Beidseitig <-> Unable to create logfile! @@ -604,12 +566,14 @@ Use Recycle Bin when deleting or overwriting files during synchronization Papierkorb für zu löschende oder überschreibende Dateien nutzen Warning Warnung -Warning: Synchronization failed for -Warnung: Synchronisation fehlgeschlagen für +Warning: Synchronization failed for %x item(s): +Warnung: Synchronisation fehlgeschlagen für %x Element(e): When \"Compare\" is triggered with this option set the following decision tree is processed: Nachdem \"Compare\" mit dieser Einstellung gestartet wurde, wird der folgende Entscheidungsbaum abgearbeitet: You can adjust the file times accordingly to resolve the issue: Die Dateizeiten können entsprechend angepasst werden, um den Fehler zu beheben: +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +Verbliebene Elemente können nochmals synchronisiert werden (OHNE dass ein erneuter Vergleich notwendig ist)! different verschieden file exists on both sides diff --git a/japanese.lng b/japanese.lng index b6c0019f..9146cdab 100644 --- a/japanese.lng +++ b/japanese.lng @@ -10,34 +10,18 @@ PB TB TB - You may try to synchronize remaining items again (WITHOUT having to re-compare)! - 残っているファイルは、再び同期することができます (再比較とは別の動作)! - already exists. Overwrite? - すでに存在します.. 上書きしますか? - directories - ディレクトリ - directory - ディレクトリ - file, - つのファイル, - files, - つのファイル, - item(s):\n\n - つのアイテム(複):\n\n kB kB - of - / - overwriting - 上書き中 - row in view - 列を表示 - rows in view - 列を表示 - to - から != files are different\n != ファイルは異なっています\n +%x directories +%x ディレクトリ +%x files, +%x 個のファイル: +%x of %y rows in view +%x / %y 行を表示 +%x of 1 row in view +%x / 1 行を表示 &Abort 情報(&A) &About... @@ -108,12 +92,14 @@ - 右側の方が新しい - same date (different size) - 日付は同一(サイズに差異あり) ----------\n ------------\n -Open-Source file synchronization- -Open-Source ファイル同期ツール- . , +1 directory +1 ディレクトリ +1 file, +1 ファイル 1. &Compare 1. 比較(&C) 1. Enter full file or directory names separated by ';' or a new line. @@ -152,8 +138,8 @@ Action 操作 Add folder pair フォルダのペアを追加 -Add to exclude filter: -除外フィルターを追加 +Add to exclude filter: +除外フィルターを追加 Adjust file times ファイル時間の調整 Adjust modification times of all files contained in the specified folder and its subfolders. This manual adaption might become necessary if you are synchronizing against a FAT32 drive and the daylight saving time is switched. For an overview about the issue see this article: @@ -166,8 +152,6 @@ An exception occured! 例外が発生しました! Apply 適用 -As a result 6 different status can be returned to categorize all files: -すべてのファイルのカテゴリ別に、6 つの異なるステータスを結果に返す事が出来ます。 As a result the files are separated into the following categories: ファイルは以下のカテゴリに分類されます: 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: @@ -178,8 +162,8 @@ Batch file created successfully! バッチファイルが作成されました! Big thanks for localizing FreeFileSync goes out to: FreeFileSync のローカライズへの協力に感謝します: -Build: -ビルド: +Build: +ビルド: Choose to hide filtered files/directories from list リストから除外したいファイル/ディレクトリを選択 Comma separated list @@ -194,8 +178,8 @@ Compare by... 比較対象... Comparing content 内容の比較中 -Comparing content of files -ファイルの内容を比較中 +Comparing content of files \"%x\" +ファイル \"%x\" の内容を比較中 Comparing... 比較中... Completed @@ -220,6 +204,8 @@ Consider this when setting up synchronization rules: You might want to avoid wri 同期規則を設定する時の備考: ディレクトリの書き込みアクセスを回避することで、これら両方の同期処理が干渉しないようにすることが考えられます。 Continue 続行 +Conversion error: +変換エラー: Copy from left to right 左から右にコピー Copy from left to right overwriting @@ -232,28 +218,20 @@ Copy new or updated files to right folder. 新しい(更新)ファイルを右フォルダにコピー Copy to clipboard\tCTRL+C クリップボードにコピー\tCTRL+C -Copying file -ファイルをコピー中 -Could not open configuration file -構成ファイルを開けませんでした -Could not open file: -ファイルを開けません: -Could not read language file -言語ファイルを読み込めません -Could not retrieve file info for: -ファイル情報を取得できません: -Could not set working directory to directory containing executable file! -実行ファイルが含まれるディレクトリは、作業ディレクトリとして利用できません! -Could not write configuration file -構成ファイルに書き込めませんでした -Could not write to -書き込みに失敗 +Copying file \"%x\" overwriting \"%y\" +ファイル \"%x\" をコピー、\"%y\" に上書き中 +Copying file \"%x\" to \"%y\" +ファイル \"%x\" を \"%y\" にコピー中 +Could not retrieve file info for: +ファイル情報を取得できません: +Could not set working directory: +作業ディレクトリが設定できません: Create a batch job 一括ジョブを作成 Create: 作成: -Creating folder -作成するフォルダ +Creating folder \"%x\" +フォルダ \"%x\" を作成中 Current operation: 現在の操作: Custom @@ -266,8 +244,6 @@ Data: データ: Date データ -Date: -日付: Daylight saving time change detected for FAT/FAT32 drive. FAT/FAT32 ドライブで検出された夏時間の変更 Delete files/folders existing on left side only @@ -278,14 +254,14 @@ Delete files\tDEL ファイルを削除\tDEL Delete: 削除: -Deleting file -ファイルを削除中 -Deleting folder -フォルダを削除中 -Directories are dependent: -ディレクトリの依存関係: -Directory does not exist: -ディレクトリが存在しません: +Deleting file \"%x\" +ファイル \"%x\" を削除中 +Deleting folder \"%x\" +フォルダ \"%x\" を削除中 +Directories are dependent: +ディレクトリの依存関係: +Directory does not exist: +ディレクトリが存在しません: Do not show graphical status and error messages but write to a logfile instead 進捗状況、及びエラーを表示しないで、代わりにログファイルに書き込む Do not show this warning again @@ -306,38 +282,28 @@ Email: E-メール: Error エラー -Error adapting modification time of file -ファイルの更新時間の適合エラー -Error changing modification time: -更新時間の変更に失敗しました: -Error converting FILETIME to SYSTEMTIME -FILETIME から SYSTEMTIME への変換エラー -Error converting FILETIME to local FILETIME -FILETIME から local FILETIME への変換エラー -Error copying file -ファイルのコピーに失敗 -Error creating directory -ディレクトリの作成に失敗 -Error deleting directory: -ディレクトリの削除エラー: -Error deleting file: -ファイルの削除エラー: -Error moving to recycle bin: -ゴミ箱への移動に失敗しました: -Error parsing configuration file -構成ファイルの構文に誤りがあります -Error reading file: -ファイル読み込みエラー: -Error traversing directory -ディレクトリの移動エラー -Error when converting int to wxString -wxString の変換エラー -Error when converting wxString to double -wxString の変換エラー(double) -Error when converting wxString to long -wxString の変換エラー(long) -Error: Source directory does not exist anymore: -エラー: ソースディレクトリが存在しません: +Error changing modification time: +時間の修正中のエラー: +Error copying file: +ファイルのコピーに失敗: +Error creating directory: +ディレクトリ作成エラー: +Error deleting directory: +ディレクトリの削除エラー: +Error deleting file: +ファイルの削除エラー: +Error moving to recycle bin: +ゴミ箱への移動に失敗しました: +Error parsing configuration file: +構成ファイルの構文に誤りがあります: +Error reading file: +ファイル読み込みエラー: +Error traversing directory: +ディレクトリの移動エラー: +Error writing file: +ファイル書き込みエラー: +Error: Source directory does not exist anymore: +エラー: ソースディレクトリが存在しません: Example 例 Exclude @@ -346,6 +312,8 @@ Exclude temporarily 一時フォルダを除外 Feedback and suggestions are welcome at: フィードバック、提案など: +File already exists. Overwrite? +ファイルは存在します、上書きしますか? File content ファイルの内容 File list exported! @@ -426,10 +394,10 @@ Ignore errors エラーを無視 Ignore next errors 次のエラーを無視 -Ignore this error, retry or abort comparison? -このエラーを無視して再試行、或いは比較を中止しますか? Ignore this error, retry or abort synchronization? このエラーを無視して再試行、或いは同期を中止しますか? +Ignore this error, retry or abort? +このエラーを無視して再試行/中断しますか? Include 含める Include temporarily @@ -442,14 +410,14 @@ Information インフォメーション Information: If you ignore the error or abort a re-compare will be necessary! インフォメーション: このエラーを無視して中断した場合は、再比較が必要です! -Initialization of Recycle Bin failed! It cannot be used! -ゴミ箱の初期化に失敗しました! 使用できない状態です! +Initialization of Recycle Bin failed! +ゴミ箱の初期化に失敗しました! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) ゴミ箱を初期化することが出来ませんでした!\n\n使用している OS が、Windows 以外の OS です。\nこの機能を使用したい場合は、作者までご連絡ください :) Left folder: 左側フォルダ: -Legend\n -履歴\n +Legend +履歴 Load configuration via...\n - this list (press DEL to delete items)\n - drag & drop to this window\n - startup parameter 構成ファイルの読み込み...\n - リスト (DEL-でアイテムを削除)\n - ウィンドウにドラッグ & ドロップ\n - 起動時のパラメータ Load from file... @@ -460,12 +428,10 @@ Mirror ->> ミラー >> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. 左側フォルダをミラーリングバックアップ: 同期完了後は、左側フォルダに合わせて右側フォルダは上書きされます。 -No valid configuration file specified: -有効な構成ファイルが選択されていません: Not all items were synchronized! Have a look at the list. すべてのアイテムは同期されていません! 詳細はリストをご覧ください。 -Nothing to synchronize. Both directories adhere to the sync-configuration! -同期対象がありません。両方のディレクトリに対する同期設定を確認してください! +Nothing to synchronize according to configuration! +構成設定に対応する同期がみつかりません! Number of files and directories that will be created 作成されたファイルとディレクトリ数 Number of files and directories that will be deleted @@ -506,18 +472,16 @@ Right folder: 右側フォルダ: S&ave configuration 構成設定を保存(&A) +Save aborted! +保存を中断! Save current configuration to file 現在の設定をファイルに保存 -Saved aborted! -保存の中断! -Scanning -スキャン Scanning... スキャン中... +Scanning: +スキャン: Select a folder フォルダを選択 -Select folder -フォルダ選択 Select variant: 変数を選択: Set filter for synchronization @@ -548,8 +512,6 @@ Stop 停止 Swap sides パネルを入れ替え -SyncJob.ffs_batch -SyncJob.ffs_batch Synchronization aborted! 同期処理を中断! Synchronization completed successfully. @@ -568,10 +530,10 @@ Synchronizing... 同期処理中... System out of memory! メモリが不足しています! -The selected file does not contain a valid configuration! -選択されたファイルには有効な構成が含まれていません! -The selected file does not exist: -選択されたファイルは存在しません: +The file does not contain a valid configuration: +このファイルには有効な構成が含まれていません: +The selected file does not exist: +選択されたファイルは存在しません: 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. Notice that the file time is allowed to deviate by up to 2 seconds. This ensures synchronization with the lower-precision file system FAT32 works correctly. この変数では、ふたつの同名ファイルが存在した場合、 それぞれのファイルサイズと最終更新日付/時間を比較します。\nファイル時間の差異が 2 秒以内の場合は検出されないということに注意してください。 (これは、FAT32システムで正確に同期を行うことができる最小値です) Time elapsed: @@ -580,12 +542,12 @@ Time shift in seconds タイムシフト(秒) Time shift: タイムシフト: -Time: -時間: +Time: +時間: Total amount of data that will be transferred 転送されたデータの総量 -Total time: -合計時間: +Total time: +合計時間: Two way <-> 両方向 <-> Unable to create logfile! @@ -604,12 +566,14 @@ Use Recycle Bin when deleting or overwriting files during synchronization 同期処理の間、ファイルの上書き/削除をする時にゴミ箱を使用 Warning 警告 -Warning: Synchronization failed for -警告: 同期処理に失敗 +Warning: Synchronization failed for %x item(s): +警告: %x アイテムの同期に失敗しました: When \"Compare\" is triggered with this option set the following decision tree is processed: この設定で \"比較\" トリガが実行された場合は、以下のツリーに従って処理されていきます。 You can adjust the file times accordingly to resolve the issue: この問題を解決するために、ファイルの時間を調整できます: +You may try to synchronize remaining items again (WITHOUT having to re-compare)! +残っているファイルは、再び同期することができます (再比較とは別の動作)! different 差異あり file exists on both sides diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index 1abf73a7..25ceb537 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -2,6 +2,7 @@ #include "globalFunctions.h" #include "resources.h" #include <wx/dc.h> +#include "../algorithm.h" const unsigned int MinimumRows = 15; @@ -18,6 +19,7 @@ public: gridData(0), lastNrRows(MinimumRows) {} + ~CustomGridTableBase() {} @@ -27,6 +29,7 @@ public: this->gridData = gridData; } + void SetGridIdentifier(int id) { gridIdentifier = id; @@ -43,13 +46,13 @@ public: return MinimumRows; //grid is initialized with this number of rows } + virtual bool IsEmptyCell( int row, int col ) { return (GetValue(row, col) == wxEmptyString); } - inline wxString evaluateCmpResult(const CompareFilesResult result, const bool selectedForSynchronization) { if (selectedForSynchronization) @@ -106,7 +109,7 @@ public: case 2: //file size return _("<Directory>"); case 3: //date - return gridLine.fileDescrLeft.lastWriteTime; + return wxEmptyString; } } else if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE) @@ -120,10 +123,13 @@ public: case 2: //file size return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrLeft.fileSize.ToString()); case 3: //date - return gridLine.fileDescrLeft.lastWriteTime; + return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrLeft.lastWriteTimeRaw); } } } + else + assert (false); + break; case 2: @@ -140,7 +146,7 @@ public: case 2: //file size return _("<Directory>"); case 3: //date - return gridLine.fileDescrRight.lastWriteTime; + return wxEmptyString; } } else if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE) @@ -154,20 +160,24 @@ public: case 2: //file size return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrRight.fileSize.ToString()); case 3: //date - return gridLine.fileDescrRight.lastWriteTime; + return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrRight.lastWriteTimeRaw); } } } + else + assert (false); + break; case 3: if (col < 1) - { - return evaluateCmpResult(gridLine.cmpResult, gridLine.selectedForSynchronization);; - } + return evaluateCmpResult(gridLine.cmpResult, gridLine.selectedForSynchronization); + else + assert (false); break; default: + assert (false); break; } } @@ -176,6 +186,7 @@ public: return wxEmptyString; } + virtual void SetValue( int row, int col, const wxString& value ) { assert (false); //should not be used, since values are retrieved directly from gridRefUI @@ -319,11 +330,10 @@ CustomGrid::CustomGrid(wxWindow *parent, const wxString& name) : wxGrid(parent, id, pos, size, style, name), scrollbarsEnabled(true), - m_gridLeft(0), m_gridRight(0), m_gridMiddle(0), - gridDataTable(0), + m_gridLeft(NULL), m_gridRight(NULL), m_gridMiddle(NULL), + gridDataTable(NULL), currentSortColumn(-1), - sortMarker(0) -{} + sortMarker(NULL) {} CustomGrid::~CustomGrid() {} @@ -335,7 +345,7 @@ bool CustomGrid::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionMod //This is done in CreateGrid instead of SetTable method since source code is generated and wxFormbuilder invokes CreatedGrid by default. gridDataTable = new CustomGridTableBase(numRows, numCols); - SetTable(gridDataTable, true, selmode); //give ownership to CustomGrid: gridDataTable is deleted automatically in CustomGrid destructor + SetTable(gridDataTable, true, selmode); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor return true; } @@ -356,7 +366,7 @@ void CustomGrid::SetScrollbar(int orientation, int position, int thumbSize, int } -//ensure that all grids are properly aligned: add some extra window space to grids that have no horizontal scrollbar +//workaround: ensure that all grids are properly aligned: add some extra window space to grids that have no horizontal scrollbar void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are not NULL in this context { int y1 = 0; @@ -372,17 +382,17 @@ void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are { int yMax = max(y1, max(y2, y3)); - if (leadingPanel == 1) //do not handle case (y1 == yMax) here!!! Avoid back coupling! + if (::leadGrid == m_gridLeft) //do not handle case (y1 == yMax) here!!! Avoid back coupling! m_gridLeft->SetMargins(0, 0); else if (y1 < yMax) m_gridLeft->SetMargins(0, 50); - if (leadingPanel == 2) + if (::leadGrid == m_gridRight) m_gridRight->SetMargins(0, 0); else if (y2 < yMax) m_gridRight->SetMargins(0, 50); - if (leadingPanel == 3) + if (::leadGrid == m_gridMiddle) m_gridMiddle->SetMargins(0, 0); else if (y3 < yMax) m_gridMiddle->SetMargins(0, 50); @@ -400,26 +410,29 @@ void CustomGrid::DoPrepareDC(wxDC& dc) wxScrollHelper::DoPrepareDC(dc); int x, y = 0; - if (leadingPanel == 1 && this == m_gridLeft) //avoid back coupling + if (this == ::leadGrid) //avoid back coupling { - GetViewStart(&x, &y); - m_gridRight->Scroll(x, y); - m_gridMiddle->Scroll(-1, y); //scroll in y-direction only - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL - } - else if (leadingPanel == 2 && this == m_gridRight) //avoid back coupling - { - GetViewStart(&x, &y); - m_gridLeft->Scroll(x, y); - m_gridMiddle->Scroll(-1, y); - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL - } - else if (leadingPanel == 3 && this == m_gridMiddle) //avoid back coupling - { - GetViewStart(&x, &y); - m_gridLeft->Scroll(-1, y); - m_gridRight->Scroll(-1, y); - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + if (this == m_gridLeft) + { + GetViewStart(&x, &y); + m_gridRight->Scroll(x, y); + m_gridMiddle->Scroll(-1, y); //scroll in y-direction only + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + } + else if (this == m_gridRight) + { + GetViewStart(&x, &y); + m_gridLeft->Scroll(x, y); + m_gridMiddle->Scroll(-1, y); + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + } + else if (this == m_gridMiddle) + { + GetViewStart(&x, &y); + m_gridLeft->Scroll(-1, y); + m_gridRight->Scroll(-1, y); + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + } } } @@ -427,12 +440,10 @@ void CustomGrid::DoPrepareDC(wxDC& dc) //these classes will scroll together, hence the name ;) void CustomGrid::setScrollFriends(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle) { - assert(gridLeft); - assert(gridRight); - assert(gridMiddle); + assert(gridLeft && gridRight && gridMiddle); - m_gridLeft = gridLeft; - m_gridRight = gridRight; + m_gridLeft = gridLeft; + m_gridRight = gridRight; m_gridMiddle = gridMiddle; assert(gridDataTable); @@ -479,3 +490,4 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col) dc.DrawBitmap(*sortMarker, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border } } + diff --git a/library/CustomGrid.h b/library/CustomGrid.h index 3547b090..bd2f3fa8 100644 --- a/library/CustomGrid.h +++ b/library/CustomGrid.h @@ -12,7 +12,7 @@ class CustomGridTableBase; //################################################################################## -extern int leadingPanel; +extern const wxGrid* leadGrid; //this global variable is not very nice... class CustomGrid : public wxGrid { @@ -26,27 +26,20 @@ public: ~CustomGrid(); - bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); - - void deactivateScrollbars(); - + virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); //overwrite virtual method to finally get rid of the scrollbars - void SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh = true); - + virtual void SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh = true); //this method is called when grid view changes: useful for parallel updating of multiple grids - void DoPrepareDC(wxDC& dc); + virtual void DoPrepareDC(wxDC& dc); + virtual void DrawColLabel(wxDC& dc, int col); + void deactivateScrollbars(); void setScrollFriends(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle); - void setGridDataTable(GridView* gridRefUI, FileCompareResult* gridData); - void updateGridSizes(); - //set sort direction indicator on UI void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap); - void DrawColLabel(wxDC& dc, int col); - private: void adjustGridHeights(); diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp index e46a2b69..eb14b2f6 100644 --- a/library/fileHandling.cpp +++ b/library/fileHandling.cpp @@ -4,9 +4,16 @@ #include "resources.h" #ifdef FFS_WIN -#include <windows.h> +#include <wx/msw/wrapwin.h> //includes "windows.h" #endif // FFS_WIN +inline +bool endsWithPathSeparator(const wxChar* name) +{ + size_t len = wxStrlen(name); + return len && (name[len - 1] == GlobalResources::FILE_NAME_SEPARATOR); +} + class RecycleBin { @@ -26,13 +33,13 @@ public: return recycleBinAvailable; } - bool moveToRecycleBin(const wxString& filename) + bool moveToRecycleBin(const Zstring& filename) { if (!recycleBinAvailable) //this method should ONLY be called if recycle bin is available - throw RuntimeException(_("Initialization of Recycle Bin failed! It cannot be used!")); + throw RuntimeException(_("Initialization of Recycle Bin failed!")); #ifdef FFS_WIN - wxString filenameDoubleNull = filename + wxChar(0); + Zstring filenameDoubleNull = filename + wxChar(0); SHFILEOPSTRUCT fileOp; fileOp.hwnd = NULL; @@ -68,21 +75,21 @@ bool FreeFileSync::recycleBinExists() inline -bool moveToRecycleBin(const wxString& filename) throw(RuntimeException) +bool moveToRecycleBin(const Zstring& filename) throw(RuntimeException) { return recyclerInstance.moveToRecycleBin(filename); } inline -void FreeFileSync::removeFile(const wxString& filename, const bool useRecycleBin) +void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) { if (!wxFileExists(filename)) return; //this is NOT an error situation: the manual deletion relies on it! if (useRecycleBin) { if (!moveToRecycleBin(filename)) - throw FileError(wxString(_("Error moving to recycle bin: ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error moving to recycle bin:")) + wxT(" \"") + filename.c_str() + wxT("\"")); return; } @@ -90,103 +97,126 @@ void FreeFileSync::removeFile(const wxString& filename, const bool useRecycleBin if (!SetFileAttributes( filename.c_str(), //address of filename FILE_ATTRIBUTE_NORMAL //attributes to set - )) throw FileError(wxString(_("Error deleting file: ")) + wxT("\"") + filename + wxT("\"")); + )) throw FileError(wxString(_("Error deleting file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); #endif //FFS_WIN if (!wxRemoveFile(filename)) - throw FileError(wxString(_("Error deleting file: ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error deleting file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); } -void FreeFileSync::removeDirectory(const wxString& directory, const bool useRecycleBin) +void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecycleBin) { if (!wxDirExists(directory)) return; //this is NOT an error situation: the manual deletion relies on it! if (useRecycleBin) { if (!moveToRecycleBin(directory)) - throw FileError(wxString(_("Error moving to recycle bin: ")) + wxT("\"") + directory + wxT("\"")); + throw FileError(wxString(_("Error moving to recycle bin:")) + wxT(" \"") + directory.c_str() + wxT("\"")); return; } - wxArrayString fileList; - wxArrayString dirList; + vector<Zstring> fileList; + vector<Zstring> dirList; try - { - //should be executed in own scope so that directory access does not disturb deletion! + { //should be executed in own scope so that directory access does not disturb deletion! getAllFilesAndDirs(directory, fileList, dirList); } catch (const FileError& e) { - throw FileError(wxString(_("Error deleting directory: ")) + wxT("\"") + directory + wxT("\"")); + throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + directory.c_str() + wxT("\"")); } - for (unsigned int j = 0; j < fileList.GetCount(); ++j) - removeFile(fileList[j], useRecycleBin); + for (unsigned int j = 0; j < fileList.size(); ++j) + removeFile(fileList[j], false); - dirList.Insert(directory, 0); //this directory will be deleted last + dirList.insert(dirList.begin(), directory); //this directory will be deleted last - for (int j = int(dirList.GetCount()) - 1; j >= 0 ; --j) + for (int j = int(dirList.size()) - 1; j >= 0 ; --j) { #ifdef FFS_WIN if (!SetFileAttributes( - dirList[j].c_str(), // address of directory name - FILE_ATTRIBUTE_NORMAL // attributes to set - )) throw FileError(wxString(_("Error deleting directory: ")) + wxT("\"") + dirList[j] + wxT("\"")); + dirList[j].c_str(), // address of directory name + FILE_ATTRIBUTE_NORMAL)) // attributes to set + throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + dirList[j].c_str() + wxT("\"")); #endif // FFS_WIN if (!wxRmdir(dirList[j])) - throw FileError(wxString(_("Error deleting directory: ")) + wxT("\"") + dirList[j] + wxT("\"")); + throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + dirList[j].c_str() + wxT("\"")); } } -void FreeFileSync::createDirectory(const wxString& directory, int level) +void FreeFileSync::createDirectory(const Zstring& directory, const int level) { if (wxDirExists(directory)) return; - if (level == 50) //catch endless loop + if (level == 50) //catch endless recursion return; //try to create directory if (wxMkdir(directory)) return; - //if not successfull try to create containing folders first - wxString createFirstDir = wxDir(directory).GetName().BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); + //if not successfull try to create parent folders first + Zstring parentDir; + if (endsWithPathSeparator(directory.c_str())) //may be valid on first level of recursion at most! Usually never true! + { + parentDir = directory.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); + parentDir = parentDir.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); + } + else + parentDir = directory.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); + + if (parentDir.empty()) return; //call function recursively - if (createFirstDir.IsEmpty()) return; - createDirectory(createFirstDir, level + 1); + createDirectory(parentDir, level + 1); //now creation should be possible if (!wxMkdir(directory)) { if (level == 0) - throw FileError(wxString(_("Error creating directory ")) + wxT("\"") + directory + wxT("\"")); + throw FileError(wxString(_("Error creating directory:")) + wxT(" \"") + directory.c_str() + wxT("\"")); } } +void FreeFileSync::copyFolderAttributes(const Zstring& source, const Zstring& target) +{ +#ifdef FFS_WIN + DWORD attr = GetFileAttributes(source.c_str()); // address of the name of a file or directory + if (attr == 0xFFFFFFFF) + throw FileError(wxString(_("Error reading file attributes:")) + wxT(" \"") + source.c_str() + wxT("\"")); + + if (!SetFileAttributes( + target.c_str(), // address of filename + attr)) // address of attributes to set + throw FileError(wxString(_("Error writing file attributes:")) + wxT(" \"") + target.c_str() + wxT("\"")); +#elif defined FFS_LINUX +//Linux doesn't use attributes for files or folders +#endif +} + + class GetAllFilesSimple : public wxDirTraverser { public: - GetAllFilesSimple(wxArrayString& files, wxArrayString& subDirectories) : + GetAllFilesSimple(vector<Zstring>& files, vector<Zstring>& subDirectories) : m_files(files), m_dirs(subDirectories) {} - wxDirTraverseResult OnDir(const wxString& dirname) { - m_dirs.Add(dirname); + m_dirs.push_back(dirname); return wxDIR_CONTINUE; } wxDirTraverseResult OnFile(const wxString& filename) { - m_files.Add(filename); + m_files.push_back(filename); return wxDIR_CONTINUE; } @@ -197,22 +227,198 @@ public: } private: - wxArrayString& m_files; - wxArrayString& m_dirs; + vector<Zstring>& m_files; + vector<Zstring>& m_dirs; }; -void FreeFileSync::getAllFilesAndDirs(const wxString& sourceDir, wxArrayString& files, wxArrayString& directories) throw(FileError) +void FreeFileSync::getAllFilesAndDirs(const Zstring& sourceDir, vector<Zstring>& files, vector<Zstring>& directories) throw(FileError) { - files.Clear(); - directories.Clear(); + files.clear(); + directories.clear(); //get all files and directories from current directory (and subdirectories) wxDir dir(sourceDir); GetAllFilesSimple traverser(files, directories); if (dir.Traverse(traverser) == (size_t)-1) - throw FileError(wxString(_("Error traversing directory ")) + wxT("\"") + sourceDir + wxT("\"")); + throw FileError(wxString(_("Error traversing directory:")) + wxT(" \"") + sourceDir.c_str() + wxT("\"")); +} + + +#ifdef FFS_WIN +class CloseOnExit +{ +public: + CloseOnExit(HANDLE searchHandle) : m_searchHandle(searchHandle) {} + + ~CloseOnExit() + { + FindClose(m_searchHandle); + } + +private: + HANDLE m_searchHandle; +}; + + +inline +void getWin32FileInformation(const WIN32_FIND_DATA& input, FreeFileSync::FileInfo& output) +{ + //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) + wxULongLong writeTimeLong(input.ftLastWriteTime.dwHighDateTime, input.ftLastWriteTime.dwLowDateTime); + writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) + writeTimeLong -= wxULongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s + output.lastWriteTimeRaw = writeTimeLong.GetLo(); //it should fit into a 32bit variable now + assert(writeTimeLong.GetHi() == 0); + + output.fileSize = wxULongLong(input.nFileSizeHigh, input.nFileSizeLow); +} + +#elif defined FFS_LINUX +class EnhancedFileTraverser : public wxDirTraverser +{ +public: + EnhancedFileTraverser(FreeFileSync::FullDetailFileTraverser* sink) : m_sink(sink) {} + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + struct stat fileInfo; + if (stat(filename.c_str(), &fileInfo) != 0) + return m_sink->OnError(Zstring(_("Could not retrieve file info for:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + + FreeFileSync::FileInfo details; + details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second + details.fileSize = fileInfo.st_size; + + return m_sink->OnFile(filename, details); + } + + virtual wxDirTraverseResult OnDir(const wxString& dirname) + { + return m_sink->OnDir(dirname); + } + + virtual wxDirTraverseResult OnOpenError(const wxString& errorText) + { + return m_sink->OnError(errorText); + } + +private: + FreeFileSync::FullDetailFileTraverser* m_sink; +}; +#endif + + +bool FreeFileSync::traverseInDetail(const Zstring& directory, FullDetailFileTraverser* sink, const int level) +{ +#ifdef FFS_WIN + if (level == 50) //catch endless recursion + { + if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directory) == wxDIR_STOP) + return false; + else + return true; + } + + Zstring directoryFormatted = directory; + if (!endsWithPathSeparator(directoryFormatted.c_str())) + directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR; + + const Zstring filespec = directoryFormatted + wxT("*.*"); + + WIN32_FIND_DATA fileMetaData; + HANDLE searchHandle = FindFirstFile(filespec.c_str(), //pointer to name of file to search for + &fileMetaData); //pointer to returned information + + if (searchHandle == INVALID_HANDLE_VALUE) + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return true; + //else: we have a problem... + if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP) + return false; + else + return true; + } + CloseOnExit dummy(searchHandle); + + do + { //don't return "." and ".." + const wxChar* name = fileMetaData.cFileName; + if ( name[0] == wxChar('.') && + ((name[1] == wxChar('.') && name[2] == wxChar('\0')) || + name[1] == wxChar('\0'))) + continue; + + const Zstring fullName = directoryFormatted + name; + if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... + { + switch (sink->OnDir(fullName)) + { + case wxDIR_IGNORE: + break; + case wxDIR_CONTINUE: + if (!traverseInDetail(fullName, sink, level + 1)) + return false; + else + break; + case wxDIR_STOP: + return false; + default: + assert(false); + break; + } + } + else //a file... + { + FileInfo details; + getWin32FileInformation(fileMetaData, details); + + switch (sink->OnFile(fullName, details)) + { + case wxDIR_IGNORE: + case wxDIR_CONTINUE: + break; + case wxDIR_STOP: + return false; + default: + assert(false); + break; + } + } + } + while (FindNextFile(searchHandle, // handle to search + &fileMetaData)); // pointer to structure for data on found file + + if (GetLastError() == ERROR_NO_MORE_FILES) + return true; //everything okay + else //an error occured + { + if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP) + return false; + else + return true; + } +#elif defined FFS_LINUX + + //use standard file traverser and enrich output with additional file information + //could be improved with own traversing algorithm for optimized performance + EnhancedFileTraverser traverser(sink); + + wxDir dir(directory); + if (dir.IsOpened()) + dir.Traverse(traverser); + + return true; +#else + adapt this +#endif } + + + + + diff --git a/library/fileHandling.h b/library/fileHandling.h index a4f43391..cd86333b 100644 --- a/library/fileHandling.h +++ b/library/fileHandling.h @@ -3,7 +3,7 @@ #include "globalFunctions.h" #include <wx/dir.h> - +#include "zstring.h" class FileError //Exception class used to notify file/directory copy/delete errors { @@ -22,15 +22,38 @@ private: namespace FreeFileSync { - void getAllFilesAndDirs(const wxString& sourceDir, wxArrayString& files, wxArrayString& directories) throw(FileError); + void getAllFilesAndDirs(const Zstring& sourceDir, vector<Zstring>& files, vector<Zstring>& directories) throw(FileError); //recycler bool recycleBinExists(); //test existence of Recycle Bin API on current system //file handling - void removeDirectory(const wxString& directory, const bool useRecycleBin); - void removeFile(const wxString& filename, const bool useRecycleBin); - void createDirectory(const wxString& directory, int level = 0); //level is used internally only + void removeDirectory(const Zstring& directory, const bool useRecycleBin); + void removeFile(const Zstring& filename, const bool useRecycleBin); + void createDirectory(const Zstring& directory, const int level = 0); //level is used internally only + void copyFolderAttributes(const Zstring& source, const Zstring& target); + +//################################ + //custom traverser with detail information about files + + struct FileInfo + { + wxULongLong fileSize; //unit: bytes! + time_t lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC + }; + + //traverser interface + class FullDetailFileTraverser + { + public: + virtual ~FullDetailFileTraverser() {} + virtual wxDirTraverseResult OnFile(const Zstring& filename, const FileInfo& details) = 0; + virtual wxDirTraverseResult OnDir(const Zstring& dirname) = 0; + virtual wxDirTraverseResult OnError(const Zstring& errorText) = 0; + }; + + bool traverseInDetail(const Zstring& directory, FullDetailFileTraverser* sink, const int level = 0); //return value and level are used internally only +//################################ } diff --git a/library/globalFunctions.cpp b/library/globalFunctions.cpp index 7e99e036..7f8b57c0 100644 --- a/library/globalFunctions.cpp +++ b/library/globalFunctions.cpp @@ -73,7 +73,7 @@ int globalFunctions::wxStringToInt(const wxString& number) if (number.ToLong(&result)) return result; else - throw RuntimeException(_("Error when converting wxString to long")); + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" wxString -> long")); } @@ -84,7 +84,7 @@ double globalFunctions::wxStringToDouble(const wxString& number) if (number.ToDouble(&result)) return result; else - throw RuntimeException(_("Error when converting wxString to double")); + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" wxString -> double")); } diff --git a/library/globalFunctions.h b/library/globalFunctions.h index add3c79d..f46a5906 100644 --- a/library/globalFunctions.h +++ b/library/globalFunctions.h @@ -44,9 +44,6 @@ namespace globalFunctions int readInt(wxInputStream& stream); //read int from file stream void writeInt(wxOutputStream& stream, const int number); //write int to filestream - - void startPerformance(); //helper method for quick performance measurement - void stopPerformance(); } diff --git a/library/misc.cpp b/library/misc.cpp index f7aea8bd..050be108 100644 --- a/library/misc.cpp +++ b/library/misc.cpp @@ -75,6 +75,9 @@ void CustomLocale::setLanguage(const int language) case wxLANGUAGE_DUTCH: languageFile = "dutch.lng"; break; + case wxLANGUAGE_CHINESE_SIMPLIFIED: + languageFile = "chinese_simple.lng"; + break; default: languageFile.clear(); currentLanguage = wxLANGUAGE_ENGLISH; @@ -123,7 +126,7 @@ void CustomLocale::setLanguage(const int language) langFile.close(); } else - wxMessageBox(wxString(_("Could not read language file ")) + wxT("\"") + wxString(languageFile.c_str(), wxConvUTF8) + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Error reading file:")) + wxT(" \"") + wxString(languageFile.c_str(), wxConvUTF8) + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR); } else ; //if languageFile is empty texts will be english per default diff --git a/library/multithreading.cpp b/library/multithreading.cpp index 753e6651..bf5918d2 100644 --- a/library/multithreading.cpp +++ b/library/multithreading.cpp @@ -1,36 +1,9 @@ #include "multithreading.h" #include <wx/utils.h> -#include <wx/app.h> -#include <wx/timer.h> -//#include "windows.h" +//#include <wx/msw/wrapwin.h> //includes "windows.h" //MessageBox(0, "hi", "", 0); -void updateUiNow() -{ - //process UI events and prevent application from "not responding" -> NO performance issue! - wxTheApp->Yield(); - - // while (wxTheApp->Pending()) - // wxTheApp->Dispatch(); -} - - -bool updateUiIsAllowed() -{ - static wxLongLong lastExec = 0; - - wxLongLong newExec = wxGetLocalTimeMillis(); - - if (newExec - lastExec >= UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary - { - lastExec = newExec; - return true; - } - return false; -} - - /*choreography: ------------- --------------- @@ -97,7 +70,7 @@ public: threadHandler->readyToReceiveResult.Lock(); threadHandler->receivingResult.Signal(); // kind of a double notice that work is completed - threadHandler->workDone = true; // workaround for wxCondition bug (wxWidgets v2.8.9, signal might geht lost) + threadHandler->workDone = true; // Workaround for wxWidgets: bug in wxCondition (wxWidgets v2.8.9, signal might geht lost) threadHandler->readyToReceiveResult.Unlock(); } diff --git a/library/multithreading.h b/library/multithreading.h index 68ad7492..bf0da145 100644 --- a/library/multithreading.h +++ b/library/multithreading.h @@ -2,6 +2,7 @@ #define MULTITHREADING_H_INCLUDED #include "statusHandler.h" +#include <wx/thread.h> class WorkerThread; diff --git a/library/processXml.cpp b/library/processXml.cpp index 2ce22b3e..04048124 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -115,10 +115,10 @@ XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename) XmlGuiConfig outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); if (!inputFile.readXmlGuiConfig(outputCfg)) //read GUI layout configuration - throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"")); return outputCfg; } @@ -132,10 +132,10 @@ XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename) XmlBatchConfig outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); if (!inputFile.readXmlBatchConfig(outputCfg)) - throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"")); return outputCfg; } @@ -149,10 +149,10 @@ XmlGlobalSettings xmlAccess::readGlobalSettings() XmlGlobalSettings outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); if (!inputFile.readXmlGlobalSettings(outputCfg)) - throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); return outputCfg; } @@ -165,7 +165,7 @@ void xmlAccess::writeGuiConfig(const wxString& filename, const XmlGuiConfig& inp //populate and write XML tree if ( !outputFile.writeXmlGuiConfig(inputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Could not write configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); return; } @@ -177,7 +177,7 @@ void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig& //populate and write XML tree if ( !outputFile.writeXmlBatchConfig(inputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Could not write configuration file ")) + wxT("\"") + filename + wxT("\"")); + throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); return; } @@ -189,7 +189,7 @@ void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& inputCfg) //populate and write XML tree if ( !outputFile.writeXmlGlobalSettings(inputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Could not write configuration file ")) + wxT("\"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); return; } @@ -338,10 +338,10 @@ bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, vector<Folder FolderPair newPair; if (!readXmlElementValue(tempString, folderPair, "Left")) return false; - newPair.leftDirectory = wxString::FromUTF8(tempString.c_str()); + newPair.leftDirectory = wxString::FromUTF8(tempString.c_str()).c_str(); if (!readXmlElementValue(tempString, folderPair, "Right")) return false; - newPair.rightDirectory = wxString::FromUTF8(tempString.c_str()); + newPair.rightDirectory = wxString::FromUTF8(tempString.c_str()).c_str(); directoryPairs.push_back(newPair); folderPair = folderPair->NextSiblingElement(); @@ -462,7 +462,6 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg) outputCfg.gui.columnWidthLeft.push_back(stringToInt(width)); else break; - leftColumn = leftColumn->NextSiblingElement(); } @@ -474,9 +473,31 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg) outputCfg.gui.columnWidthRight.push_back(stringToInt(width)); else break; - rightColumn = rightColumn->NextSiblingElement(); } + + //read column positions + TiXmlElement* leftColumnPos = TiXmlHandle(mainWindow).FirstChild("LeftColumnPositions").FirstChild("Position").ToElement(); + while (leftColumnPos) + { + const char* width = leftColumnPos->GetText(); + if (width) //may be NULL!! + outputCfg.gui.columnPositionsLeft.push_back(stringToInt(width)); + else + break; + leftColumnPos = leftColumnPos->NextSiblingElement(); + } + + TiXmlElement* rightColumnPos = TiXmlHandle(mainWindow).FirstChild("RightColumnPositions").FirstChild("Position").ToElement(); + while (rightColumnPos) + { + const char* width = rightColumnPos->GetText(); + if (width) //may be NULL!! + outputCfg.gui.columnPositionsRight.push_back(stringToInt(width)); + else + break; + rightColumnPos = rightColumnPos->NextSiblingElement(); + } } @@ -589,8 +610,8 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const TiXmlElement* folderPair = new TiXmlElement("Pair"); folders->LinkEndChild(folderPair); - addXmlElement(folderPair, "Left", string((i->leftDirectory).ToUTF8())); - addXmlElement(folderPair, "Right", string((i->rightDirectory).ToUTF8())); + addXmlElement(folderPair, "Left", string(wxString(i->leftDirectory.c_str()).ToUTF8())); + addXmlElement(folderPair, "Right", string(wxString(i->rightDirectory.c_str()).ToUTF8())); } //########################################################### @@ -726,6 +747,18 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg) for (unsigned int i = 0; i < inputCfg.gui.columnWidthRight.size(); ++i) addXmlElement(rightColumn, "Width", inputCfg.gui.columnWidthRight[i]); + //write column positions + TiXmlElement* leftColumnPos = new TiXmlElement("LeftColumnPositions"); + mainWindow->LinkEndChild(leftColumnPos); + + for (unsigned int i = 0; i < inputCfg.gui.columnPositionsLeft.size(); ++i) + addXmlElement(leftColumnPos, "Position", inputCfg.gui.columnPositionsLeft[i]); + + TiXmlElement* rightColumnPos = new TiXmlElement("RightColumnPositions"); + mainWindow->LinkEndChild(rightColumnPos); + + for (unsigned int i = 0; i < inputCfg.gui.columnPositionsRight.size(); ++i) + addXmlElement(rightColumnPos, "Position", inputCfg.gui.columnPositionsRight[i]); //################################################################### //write batch settings @@ -735,3 +768,42 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg) return true; } + + +int xmlAccess::retrieveSystemLanguage() //map language dialects +{ + const int lang = wxLocale::GetSystemLanguage(); + + switch (lang) + { + case wxLANGUAGE_GERMAN_AUSTRIAN: + case wxLANGUAGE_GERMAN_BELGIUM: + case wxLANGUAGE_GERMAN_LIECHTENSTEIN: + case wxLANGUAGE_GERMAN_LUXEMBOURG: + case wxLANGUAGE_GERMAN_SWISS: + return wxLANGUAGE_GERMAN; + + case wxLANGUAGE_FRENCH_BELGIAN: + case wxLANGUAGE_FRENCH_CANADIAN: + case wxLANGUAGE_FRENCH_LUXEMBOURG: + case wxLANGUAGE_FRENCH_MONACO: + case wxLANGUAGE_FRENCH_SWISS: + return wxLANGUAGE_FRENCH; + + //case wxLANGUAGE_JAPANESE: + + case wxLANGUAGE_DUTCH_BELGIAN: + return wxLANGUAGE_DUTCH; + + case wxLANGUAGE_CHINESE: + case wxLANGUAGE_CHINESE_TRADITIONAL: + case wxLANGUAGE_CHINESE_HONGKONG: + case wxLANGUAGE_CHINESE_MACAU: + case wxLANGUAGE_CHINESE_SINGAPORE: + case wxLANGUAGE_CHINESE_TAIWAN: + return wxLANGUAGE_CHINESE_SIMPLIFIED; + + default: + return lang; + } +} diff --git a/library/processXml.h b/library/processXml.h index e359e7b0..bc81556e 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -3,7 +3,6 @@ #include "../FreeFileSync.h" #include "tinyxml/tinyxml.h" -#include <wx/intl.h> using namespace FreeFileSync; @@ -42,13 +41,14 @@ namespace xmlAccess bool silent; }; + int retrieveSystemLanguage(); struct XmlGlobalSettings { struct _Global { _Global() : - programLanguage(wxLocale::GetSystemLanguage()), + programLanguage(retrieveSystemLanguage()), #ifdef FFS_WIN dstCheckActive(true), #endif @@ -77,6 +77,8 @@ namespace xmlAccess bool isMaximized; vector<int> columnWidthLeft; vector<int> columnWidthRight; + vector<int> columnPositionsLeft; + vector<int> columnPositionsRight; } gui; //struct _Batch diff --git a/library/resources.cpp b/library/resources.cpp index 68eeb4d6..9169bf85 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -3,6 +3,7 @@ #include <wx/zipstrm.h> #include <wx/image.h> #include <wx/icon.h> +#include <wx/mstream.h> #include "globalFunctions.h" #ifdef FFS_WIN @@ -111,6 +112,24 @@ GlobalResources::~GlobalResources() } +void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation* animation) +{ + //Workaround for wxWidgets: + //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load() + //luckily this method call is very fast: below measurement precision! + vector<unsigned char> data; + data.reserve(10000); + + int newValue = 0; + while ((newValue = zipInput.GetC()) != wxEOF) + data.push_back(newValue); + + wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data + + animation->Load(seekAbleStream, wxANIMATION_TYPE_GIF); +} + + void GlobalResources::load() { wxFileInputStream input(wxT("Resources.dat")); @@ -121,21 +140,22 @@ void GlobalResources::load() wxZipInputStream resourceFile(input); - wxZipEntry* entry; + wxZipEntry* entry = NULL; map<wxString, wxBitmap*>::iterator bmp; while ((entry = resourceFile.GetNextEntry())) { wxString name = entry->GetName(); - //just to be sure: search if entry is available in map + //search if entry is available in map if ((bmp = bitmapResource.find(name)) != bitmapResource.end()) *(bmp->second) = wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + else if (name == wxT("money.gif")) + loadAnimFromZip(resourceFile, animationMoney); + else if (name == wxT("working.gif")) + loadAnimFromZip(resourceFile, animationSync); } } - animationMoney->LoadFile(wxT("Resources.a01")); - animationSync->LoadFile(wxT("Resources.a02")); - #ifdef FFS_WIN programIcon = new wxIcon(wxT("ffsIcon1")); #else diff --git a/library/sorting.h b/library/sorting.h index bf643176..560e246a 100644 --- a/library/sorting.h +++ b/library/sorting.h @@ -3,6 +3,7 @@ #include "../FreeFileSync.h" #include "resources.h" +#include "globalFunctions.h" enum SideToSort @@ -12,34 +13,6 @@ enum SideToSort }; -template <bool sortAscending> -inline -bool cmpString(const wxString& a, const wxString& b) -{ - if (a.IsEmpty()) - return false; //if a and b are empty: false, if a empty, b not empty: also false, since empty rows should appear at the end - else if (b.IsEmpty()) - return true; //empty rows after filled rows: return true - - //if a and b not empty: - if (sortAscending) - return (a < b); - else - return (a > b); -} - - -template <bool sortAscending> -inline -bool cmpLargeInt(const wxULongLong& a, const wxULongLong& b) -{ - if (sortAscending) - return (a < b); - else - return (a > b); -} - - template <SideToSort side> inline void getDescrLine(const FileCompareLine& a, const FileCompareLine& b, const FileDescrLine*& descrLineA, const FileDescrLine*& descrLineB) @@ -54,49 +27,68 @@ void getDescrLine(const FileCompareLine& a, const FileCompareLine& b, const File descrLineA = &a.fileDescrRight; descrLineB = &b.fileDescrRight; } - else assert(false); + else + assert(false); } +template <bool sortAscending> inline -wxChar formatChar(const wxChar& c) +bool stringSmallerThan(const wxChar* stringA, const wxChar* stringB) { - return c; - //return wxTolower(c); <- this is slow as hell! sorting slower by factor 10 +#ifdef FFS_WIN //case-insensitive comparison! + return sortAscending ? + FreeFileSync::compareStringsWin32(stringA, stringB) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! + FreeFileSync::compareStringsWin32(stringA, stringB) > 0; +#else + while (*stringA == *stringB) + { + if (*stringA == wxChar(0)) //strings are equal + return false; + + ++stringA; + ++stringB; + } + return sortAscending ? *stringA < *stringB : *stringA > *stringB; //wxChar(0) is handled correctly +#endif } inline int compareString(const wxChar* stringA, const wxChar* stringB, const int lengthA, const int lengthB) { +#ifdef FFS_WIN //case-insensitive comparison! + return FreeFileSync::compareStringsWin32(stringA, stringB, lengthA, lengthB); //way faster than wxString::CmpNoCase() in the windows build!!! +#else int i = 0; if (lengthA == lengthB) { for (i = 0; i < lengthA; ++i) { - if (formatChar(stringA[i]) != formatChar(stringB[i])) + if (stringA[i] != stringB[i]) break; } - return i == lengthA ? 0 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1; + return i == lengthA ? 0 : stringA[i] < stringB[i] ? -1 : 1; } else if (lengthA < lengthB) { for (i = 0; i < lengthA; ++i) { - if (formatChar(stringA[i]) != formatChar(stringB[i])) + if (stringA[i] != stringB[i]) break; } - return i == lengthA ? -1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1; + return i == lengthA ? -1 : stringA[i] < stringB[i] ? -1 : 1; } else { for (i = 0; i < lengthB; ++i) { - if (formatChar(stringA[i]) != formatChar(stringB[i])) + if (stringA[i] != stringB[i]) break; } - return i == lengthB ? 1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1; + return i == lengthB ? 1 : stringA[i] < stringB[i] ? -1 : 1; } +#endif } @@ -119,43 +111,23 @@ bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b) return true; else { - const wxChar* stringA = NULL; - const wxChar* stringB = NULL; - int lenghtA = 0; - int lenghtB = 0; + const wxChar* stringA = descrLineA->relativeName.c_str(); + const wxChar* stringB = descrLineB->relativeName.c_str(); - int pos = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end - if (pos == wxNOT_FOUND) - { - stringA = descrLineA->relativeName.c_str(); - lenghtA = descrLineA->relativeName.Len(); - } - else - { - stringA = descrLineA->relativeName.c_str() + pos + 1; - lenghtA = descrLineA->relativeName.Len() - (pos + 1); - } + size_t pos = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end + if (pos != string::npos) + stringA += pos + 1; pos = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end - if (pos == wxNOT_FOUND) - { - stringB = descrLineB->relativeName.c_str(); - lenghtB = descrLineB->relativeName.Len(); - } - else - { - stringB = descrLineB->relativeName.c_str() + pos + 1; - lenghtB = descrLineB->relativeName.Len() - (pos + 1); - } + if (pos != string::npos) + stringB += pos + 1; - int rv = compareString(stringA, stringB, lenghtA, lenghtB); - return sortAscending ? (rv == -1) : (rv == 1); + return stringSmallerThan<sortAscending>(stringA, stringB); } } template <bool sortAscending, SideToSort side> -inline bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b) { const FileDescrLine* descrLineA = NULL; @@ -163,67 +135,59 @@ bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b) getDescrLine<side>(a, b, descrLineA, descrLineB); //extract relative name and filename - const wxChar* relStringA = NULL; - const wxChar* fileStringA = NULL; - int relLenghtA = 0; + const wxChar* relStringA = descrLineA->relativeName.c_str(); //mustn't be NULL for CompareString() API to work correctly + const wxChar* fileStringA = relStringA; + int relLengthA = 0; int fileLengthA = 0; + if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) - { - relStringA = descrLineA->relativeName.c_str(); - relLenghtA = descrLineA->relativeName.Len(); - } + relLengthA = descrLineA->relativeName.length(); else if (descrLineA->objType == FileDescrLine::TYPE_FILE) { - relLenghtA = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end - if (relLenghtA == wxNOT_FOUND) + relLengthA = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end + if (relLengthA == wxNOT_FOUND) { - relLenghtA = 0; - fileStringA = descrLineA->relativeName.c_str(); - fileLengthA = descrLineA->relativeName.Len(); + relLengthA = 0; + fileLengthA = descrLineA->relativeName.length(); } else { - relStringA = descrLineA->relativeName.c_str(); - fileStringA = descrLineA->relativeName.c_str() + relLenghtA + 1; - fileLengthA = descrLineA->relativeName.Len() - (relLenghtA + 1); + fileStringA += relLengthA + 1; + fileLengthA = descrLineA->relativeName.length() - (relLengthA + 1); } } else return false; //empty rows should be on end of list - const wxChar* relStringB = NULL; - const wxChar* fileStringB = NULL; - int relLenghtB = 0; + const wxChar* relStringB = descrLineB->relativeName.c_str(); //mustn't be NULL for CompareString() API to work correctly + const wxChar* fileStringB = relStringB; + int relLengthB = 0; int fileLengthB = 0; + if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) - { - relStringB = descrLineB->relativeName.c_str(); - relLenghtB = descrLineB->relativeName.Len(); - } + relLengthB = descrLineB->relativeName.length(); else if (descrLineB->objType == FileDescrLine::TYPE_FILE) { - relLenghtB = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end - if (relLenghtB == wxNOT_FOUND) + relLengthB = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end + if (relLengthB == wxNOT_FOUND) { - relLenghtB = 0; - fileStringB = descrLineB->relativeName.c_str(); - fileLengthB = descrLineB->relativeName.Len(); + relLengthB = 0; + fileLengthB = descrLineB->relativeName.length(); } else { - relStringB = descrLineB->relativeName.c_str(); - fileStringB = descrLineB->relativeName.c_str() + relLenghtB + 1; - fileLengthB = descrLineB->relativeName.Len() - (relLenghtB + 1); + fileStringB += relLengthB + 1; + fileLengthB = descrLineB->relativeName.length() - (relLengthB + 1); } } else return true; //empty rows should be on end of list //compare relative names without filenames first - int rv = compareString(relStringA, relStringB, relLenghtA, relLenghtB); + int rv = compareString(relStringA, relStringB, relLengthA, relLengthB); if (rv != 0) - return sortAscending ? (rv == -1) : (rv == 1); + return sortAscending ? (rv < 0) : (rv > 0); else //compare the filenames { if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) //directories shall appear before files @@ -231,8 +195,9 @@ bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b) else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) return true; - rv = compareString(fileStringA, fileStringB, fileLengthA, fileLengthB); - return sortAscending ? (rv == -1) : (rv == 1); + return sortAscending ? + compareString(fileStringA, fileStringB, fileLengthA, fileLengthB) < 0 : + compareString(fileStringA, fileStringB, fileLengthA, fileLengthB) > 0; } } @@ -254,8 +219,10 @@ bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b) return false; else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) return true; - else //use unformatted filesizes and sort by size - return cmpLargeInt<sortAscending>(descrLineA->fileSize, descrLineB->fileSize); + else + return sortAscending ? + descrLineA->fileSize < descrLineB->fileSize : + descrLineA->fileSize > descrLineB->fileSize; } @@ -267,7 +234,19 @@ bool sortByDate(const FileCompareLine& a, const FileCompareLine& b) const FileDescrLine* descrLineB = NULL; getDescrLine<side>(a, b, descrLineA, descrLineB); - return cmpString<sortAscending>(descrLineA->lastWriteTime, descrLineB->lastWriteTime); + //presort types: first files, then directories then empty rows + if (descrLineA->objType == FileDescrLine::TYPE_NOTHING) + return false; //empty rows always last + else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING) + return true; //empty rows always last + else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) + return false; + else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) + return true; + else + return sortAscending ? + descrLineA->lastWriteTimeRaw < descrLineB->lastWriteTimeRaw : + descrLineA->lastWriteTimeRaw > descrLineB->lastWriteTimeRaw; } diff --git a/library/statusHandler.cpp b/library/statusHandler.cpp new file mode 100644 index 00000000..e19c9904 --- /dev/null +++ b/library/statusHandler.cpp @@ -0,0 +1,28 @@ +#include "statusHandler.h" +#include <wx/app.h> +#include <wx/timer.h> + + +void updateUiNow() +{ + //process UI events and prevent application from "not responding" -> NO performance issue! + wxTheApp->Yield(); + + // while (wxTheApp->Pending()) + // wxTheApp->Dispatch(); +} + + +bool updateUiIsAllowed() +{ + static wxLongLong lastExec = 0; + + wxLongLong newExec = wxGetLocalTimeMillis(); + + if (newExec - lastExec >= UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary + { + lastExec = newExec; + return true; + } + return false; +} diff --git a/library/statusHandler.h b/library/statusHandler.h index 70f8c2d8..4c12035d 100644 --- a/library/statusHandler.h +++ b/library/statusHandler.h @@ -2,7 +2,7 @@ #define STATUSHANDLER_H_INCLUDED #include <wx/string.h> -#include <wx/thread.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 @@ -21,7 +21,7 @@ public: enum Response { - CONTINUE_NEXT = 10, + IGNORE_ERROR = 10, RETRY }; virtual Response reportError(const wxString& text) = 0; diff --git a/library/zstring.cpp b/library/zstring.cpp new file mode 100644 index 00000000..b84c9512 --- /dev/null +++ b/library/zstring.cpp @@ -0,0 +1,396 @@ +#include "zstring.h" +#include <wx/intl.h> +#include "globalFunctions.h" + + +#ifdef FFS_WIN +#include <wx/msw/wrapwin.h> //includes "windows.h" +#endif //FFS_WIN + + +#ifdef __WXDEBUG__ +int allocCount = 0; //test Zstring for memory leaks + +void testZstringForMemoryLeak() +{ + if (allocCount != 0) +#ifdef FFS_WIN + MessageBox(NULL, wxT("Fatal Error! Allocation problem with Zstring! (No problem if it occures while Unit testing only!)"), wxString::Format(wxT("%i"), allocCount), 0); +#else + throw; +#endif //FFS_WIN +} +#endif + + +#ifdef FFS_WIN +int FreeFileSync::compareStringsWin32(const wchar_t* a, const wchar_t* b) +{ + return lstrcmpi( + a, //address of first string + b); //address of second string +} + + +//equivalent implementation, but slightly(!!!) slower: +int FreeFileSync::compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount, const int bCount) +{ + int rv = CompareString( + LOCALE_USER_DEFAULT, //locale identifier + NORM_IGNORECASE, //comparison-style options + a, //pointer to first string + aCount, //size, in bytes or characters, of first string + b, //pointer to second string + bCount); //size, in bytes or characters, of second string + + if (rv == 0) + throw RuntimeException(wxString(_("Error comparing strings!"))); + else + return rv - 2; +} +#endif + + +size_t Zstring::Replace(const defaultChar* old, const defaultChar* replacement, bool replaceAll) +{ + const size_t oldLen = defaultLength(old); + const size_t replacementLen = defaultLength(replacement); + size_t uiCount = 0; //count of replacements made + + size_t pos = 0; + while (true) + { + pos = find(old, pos); + if (pos == npos) + break; + + replace(pos, oldLen, replacement, replacementLen); + pos += replacementLen; //move past the string that was replaced + + ++uiCount; //increase replace count + + // stop now? + if (!replaceAll) + break; + } + return uiCount; +} + + +bool matchesHelper(const defaultChar* string, const defaultChar* mask) +{ + for (defaultChar ch; (ch = *mask) != 0; ++mask) + { + switch (ch) + { + case defaultChar('?'): + if (*string == 0) + return false; + else + ++string; + break; + + case defaultChar('*'): + //advance to next non-*/? char + do + { + ++mask; + ch = *mask; + } + while (ch == defaultChar('*') || ch == defaultChar('?')); + //if match ends with '*': + if (ch == defaultChar(0)) + return true; + + ++mask; + while ((string = defaultStrFind(string, ch)) != NULL) + { + if (matchesHelper(string + 1, mask)) + return true; + ++string; + } + return false; + break; + + default: + if (*string != ch) + return false; + else + ++string; + } + } + return *string == 0; +} + + +bool Zstring::Matches(const defaultChar* mask) const +{ + return matchesHelper(c_str(), mask); +} + + +Zstring& Zstring::Trim(bool fromRight) +{ + const size_t thisLen = length(); + if (thisLen == 0) + return *this; + + if (fromRight) + { + const defaultChar* cursor = data + thisLen - 1; + while (cursor != data - 1 && defaultIsWhiteSpace(*cursor)) //break when pointing one char further than last skipped element + --cursor; + ++cursor; + + const size_t newLength = cursor - data; + if (newLength != thisLen) + { + if (descr->refCount > 1) //allocate new string + *this = Zstring(data, newLength); + else //overwrite this string + descr->length = newLength; + } + } + else + { + defaultChar* cursor = data; + defaultChar ch; + while ((ch = *cursor) != 0 && defaultIsWhiteSpace(ch)) + ++cursor; + + const size_t diff = cursor - data; + if (diff) + { + if (descr->refCount > 1) //allocate new string + *this = Zstring(cursor, thisLen - diff); + else + { //overwrite this string + data = cursor; //no problem when deallocating data, since descr points to begin of allocated area + descr->capacity -= diff; + descr->length -= diff; + } + } + } + + return *this; +} + + +Zstring& Zstring::MakeLower() +{ + const size_t thisLen = length(); + if (thisLen == 0) + return *this; + + if (descr->refCount > 1) //allocate new string + { + StringDescriptor* newDescr; + defaultChar* newData; + const size_t newCapacity = getCapacityToAllocate(thisLen); + allocate(1, thisLen, newCapacity, newDescr, newData); + + for (unsigned int i = 0; i < thisLen; ++i) + newData[i] = defaultToLower(data[i]); + newData[thisLen] = 0; + + decRef(); + descr = newDescr; + data = newData; + } + else + { //overwrite this string + for (unsigned int i = 0; i < thisLen; ++i) + data[i] = defaultToLower(data[i]); + } + + return *this; +} + + +//############################################################### +//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(const 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 (data[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); + + if (n2 != 0) + { + const size_t oldLen = length(); + if (oldLen == 0) + { + assert(n1 == 0); + return *this = Zstring(str, n2); + } + + const size_t newLen = oldLen - n1 + n2; + if (n1 < n2 || descr->refCount > 1) + { //allocate a new string + const size_t newCapacity = getCapacityToAllocate(newLen); + + StringDescriptor* newDescr; + defaultChar* newData; + allocate(1, newLen, newCapacity, newDescr, newData); + //StringDescriptor* newDescr = new StringDescriptor(1, newLen, newCapacity); + //defaultChar* newData = new defaultChar[newCapacity + 1]; + + //assemble new string with replacement + memcpy(newData, data, pos1 * sizeof(defaultChar)); + memcpy(newData + pos1, str, n2 * sizeof(defaultChar)); + memcpy(newData + pos1 + n2, data + pos1 + n1, (oldLen - pos1 - n1) * sizeof(defaultChar)); + newData[newLen] = 0; + + decRef(); + data = newData; + descr = newDescr; + } + else + { //overwrite current string + memcpy(data + pos1, str, n2 * sizeof(defaultChar)); + if (n1 > n2) + { + 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 (sourceLen == 0) + return *this = Zstring(); + + if (descr->refCount > 1 || descr->capacity < sourceLen) //allocate new string + *this = Zstring(source, sourceLen); + else + { //overwrite this string + memcpy(data, source, sourceLen * sizeof(defaultChar)); + data[sourceLen] = 0; + descr->length = sourceLen; + } + 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; + copyBeforeWrite(newLen); + + memcpy(data + thisLen, other.c_str(), otherLen * sizeof(defaultChar)); + data[newLen] = 0; + 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; + copyBeforeWrite(newLen); + + memcpy(data + thisLen, other, otherLen * sizeof(defaultChar)); + data[newLen] = 0; + descr->length = newLen; + } + return *this; +} + + +Zstring& Zstring::operator+=(defaultChar ch) +{ + const size_t oldLen = length(); + copyBeforeWrite(oldLen + 1); + data[oldLen] = ch; + data[oldLen + 1] = 0; + ++descr->length; + return *this; +} + + +void Zstring::copyBeforeWrite(const size_t capacityNeeded) +{ + assert(capacityNeeded != 0); + + if (descr->refCount > 1) + { //allocate a new string + const size_t oldLength = length(); + const size_t newCapacity = getCapacityToAllocate(capacityNeeded); + + StringDescriptor* newDescr; + defaultChar* newData; + allocate(1, oldLength, newCapacity, newDescr, newData); + //StringDescriptor* newDescr = new StringDescriptor(1, oldLength, newCapacity); + //defaultChar* newData = new defaultChar[newCapacity + 1]; + + if (oldLength) + { + assert(oldLength <= newCapacity); + memcpy(newData, data, oldLength * sizeof(defaultChar)); + newData[oldLength] = 0; + } + decRef(); + descr = newDescr; + data = newData; + } + else if (descr->capacity < capacityNeeded) + { //try to resize the current string (allocate anew if necessary) + const size_t newCapacity = getCapacityToAllocate(capacityNeeded); + + descr = (StringDescriptor*) realloc(descr, sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(defaultChar)); + if (descr == NULL) + throw; //std::bad_alloc& e + data = (defaultChar*)(descr + 1); + descr->capacity = newCapacity; + } +} diff --git a/library/zstring.h b/library/zstring.h new file mode 100644 index 00000000..00590d4f --- /dev/null +++ b/library/zstring.h @@ -0,0 +1,580 @@ +/*************************************************************** + * Purpose: High performance string class + * Author: ZenJu (zhnmju123@gmx.de) + * Created: Jan. 2009 + **************************************************************/ + +#ifndef ZSTRING_H_INCLUDED +#define ZSTRING_H_INCLUDED + +#include <wx/string.h> + +namespace FreeFileSync +{ +#ifdef FFS_WIN + //super fast case-insensitive string comparison: way faster than wxString::CmpNoCase()!!! + int compareStringsWin32(const wchar_t* a, const wchar_t* b); + int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount, const int bCount); +#endif //FFS_WIN +} + +#ifdef FFS_WIN +#define ZSTRING_WIDE_CHAR //use wide character strings + +#elif defined FFS_LINUX +#define ZSTRING_CHAR //use char strings +#endif + + +#ifdef ZSTRING_CHAR +typedef char defaultChar; +#elif defined ZSTRING_WIDE_CHAR +typedef wchar_t defaultChar; +#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(const wxString& source); //string is copied: O(length) + ~Zstring(); + + operator const defaultChar*() const; //implicit conversion to C string + operator const wxString() const; //implicit conversion to wxString + + //wxWidgets functions + bool StartsWith(const defaultChar* begin) const; + bool StartsWith(const Zstring& begin) const; + bool EndsWith(const defaultChar* end) const; + bool EndsWith(const Zstring& end) const; +#ifdef FFS_WIN + int CmpNoCase(const defaultChar* other) const; + int CmpNoCase(const Zstring& other) const; +#endif + int Cmp(const defaultChar* other) const; + int Cmp(const Zstring& other) const; + size_t Replace(const defaultChar* old, const defaultChar* replacement, bool replaceAll = true); + Zstring AfterLast(defaultChar ch) const; + Zstring BeforeLast(defaultChar ch) const; + size_t Find(defaultChar ch, bool fromEnd) const; + bool Matches(const defaultChar* mask) const; + Zstring& Trim(bool fromRight); //from right or left + Zstring& MakeLower(); + + //std::string functions + size_t length() const; + const defaultChar* c_str() const; + Zstring substr(size_t pos = 0, size_t len = npos) const; + bool empty() const; + int compare(const defaultChar* other) const; + int compare(const Zstring& other) const; + int compare(const size_t pos1, const size_t n1, const defaultChar* other) const; + size_t find(const defaultChar* str, const size_t pos = 0 ) const; + size_t find(const defaultChar ch, const size_t pos = 0) const; + size_t rfind(const defaultChar ch, size_t pos = npos) const; + Zstring& replace(size_t pos1, size_t n1, const defaultChar* str, size_t n2); + + Zstring& operator=(const Zstring& source); + Zstring& operator=(const defaultChar* source); + + bool operator==(const Zstring& other) const; + bool operator==(const defaultChar* other) const; + + Zstring& operator+=(const Zstring& other); + Zstring& operator+=(const defaultChar* other); + Zstring& operator+=(defaultChar ch); + + Zstring operator+(const Zstring& string2) const; + Zstring operator+(const defaultChar* string2) const; + Zstring operator+(const defaultChar ch) const; + + static const size_t npos = static_cast<size_t>(-1); + +private: + void initAndCopy(const defaultChar* source, size_t length); + void incRef(); //support for reference-counting + void decRef(); // + void copyBeforeWrite(const size_t capacityNeeded); //and copy-on-write + + struct StringDescriptor + { + StringDescriptor(const unsigned int refC, const size_t len, const size_t cap) : refCount(refC), length(len), capacity(cap) {} + unsigned int refCount; + size_t length; + size_t capacity; //allocated length without null-termination + }; + static void allocate(const unsigned int newRefCount, const size_t newLength, const size_t newCapacity, Zstring::StringDescriptor*& newDescr, defaultChar*& newData); + + StringDescriptor* descr; + defaultChar* data; +}; + + +//####################################################################################### +//begin of implementation + +#ifdef ZSTRING_CHAR +inline +size_t defaultLength(const char* input) +{ + return strlen(input); +} + +inline +int defaultCompare(const char* str1, const char* str2) +{ + return strcmp(str1, str2); +} + +inline +int defaultCompare(const char* str1, const char* str2, const size_t count) +{ + return strncmp(str1, str2, count); +} + +inline +char* defaultStrFind(const char* str1, const char* str2) +{ + return strstr(str1, str2); +} + +inline +char* defaultStrFind(const char* str1, int ch) +{ + return strchr(str1, ch); +} + +inline +bool defaultIsWhiteSpace(const char 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) && isspace(ch) != 0; +} + +inline +char defaultToLower(const char ch) +{ + return tolower(ch); +} + +#elif defined ZSTRING_WIDE_CHAR +inline +size_t defaultLength(const wchar_t* input) +{ + return wcslen(input); +} + +inline +int defaultCompare(const wchar_t* str1, const wchar_t* str2) +{ + return wcscmp(str1, str2); +} + +inline +int defaultCompare(const wchar_t* str1, const wchar_t* str2, const size_t count) +{ + return wcsncmp(str1, str2, count); +} + +inline +wchar_t* defaultStrFind(const wchar_t* str1, const wchar_t* str2) +{ + return wcsstr(str1, str2); +} + +inline +wchar_t* defaultStrFind(const wchar_t* str1, int ch) +{ + return wcschr(str1, ch); +} + +inline +bool defaultIsWhiteSpace(const 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; +} + +inline +wchar_t defaultToLower(const wchar_t ch) +{ + return towlower(ch); +} +#endif + + +#ifdef __WXDEBUG__ +extern int allocCount; //test Zstring for memory leaks +void testZstringForMemoryLeak(); +#endif + + +inline +void Zstring::allocate(const unsigned int newRefCount, + const size_t newLength, + const size_t newCapacity, + StringDescriptor*& newDescr, + defaultChar*& newData) +{ //allocate and set data for new string + if (newCapacity) + { + newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(defaultChar)); + if (newDescr == NULL) + throw; //std::bad_alloc& e + newData = (defaultChar*)(newDescr + 1); + } + else + { + newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor)); + if (newDescr == NULL) + throw; //std::bad_alloc& e + newData = NULL; + } + + newDescr->refCount = newRefCount; + newDescr->length = newLength; + newDescr->capacity = newCapacity; + +#ifdef __WXDEBUG__ + ++allocCount; //test Zstring for memory leaks + + static bool isRegistered = false; + if (!isRegistered) + { + isRegistered = true; + atexit(testZstringForMemoryLeak); + } +#endif +} + + +inline +Zstring::Zstring() +{ + allocate(1, 0, 0, descr, data); +} + + +inline +Zstring::Zstring(const defaultChar* source) +{ + initAndCopy(source, defaultLength(source)); +} + + +inline +Zstring::Zstring(const defaultChar* source, size_t length) +{ + initAndCopy(source, length); +} + + +inline +Zstring::Zstring(const Zstring& source) +{ + descr = source.descr; + data = source.data; + incRef(); //reference counting! +} + + +inline +Zstring::Zstring(const wxString& source) +{ + initAndCopy(source.c_str(), source.length()); +} + + +inline +Zstring::~Zstring() +{ + decRef(); +} + + +inline +size_t getCapacityToAllocate(const size_t length) +{ + return (length + (19 - length % 16)); //allocate some additional length to speed up concatenation +} + + +inline +void Zstring::initAndCopy(const defaultChar* source, size_t length) +{ + const size_t newCapacity = getCapacityToAllocate(length); + allocate(1, length, newCapacity, descr, data); + memcpy(data, source, length * sizeof(defaultChar)); + data[length] = 0; +} + + +inline +void Zstring::incRef() +{ + assert(descr); + ++descr->refCount; +} + + +inline +void Zstring::decRef() +{ + assert(descr && descr->refCount >= 1); + if (--descr->refCount == 0) + { + assert(descr); //descr points to the begin of the allocated memory block + free(descr); //this must NEVER be changed!! E.g. Trim() relies on descr being start of allocated memory block +#ifdef __WXDEBUG__ + --allocCount; //test Zstring for memory leaks +#endif + } +} + + +#ifdef FFS_WIN +inline +int Zstring::CmpNoCase(const defaultChar* other) const +{ + return FreeFileSync::compareStringsWin32(c_str(), other); //way faster than wxString::CmpNoCase()!! +} + + +inline +int Zstring::CmpNoCase(const Zstring& other) const +{ + return FreeFileSync::compareStringsWin32(c_str(), other.c_str()); //way faster than wxString::CmpNoCase()!! +} +#endif + + +inline +Zstring::operator const defaultChar*() const +{ + return c_str(); +} + + +inline +Zstring& Zstring::operator=(const Zstring& source) +{ + if (this != &source) + { + decRef(); + descr = source.descr; + data = source.data; + incRef(); + } + return *this; +} + + +inline +size_t Zstring::Find(defaultChar ch, bool fromEnd) const +{ + if (fromEnd) + return rfind(ch, npos); + else + return 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 +{ + size_t pos = rfind(ch, npos); + if (pos == npos ) + return *this; + else + return c_str() + pos + 1; +} + + +// get all characters before the last occurence of ch +// (returns empty string if ch not found) +inline +Zstring Zstring::BeforeLast(defaultChar ch) const +{ + size_t pos = rfind(ch, npos); + + if (pos != npos && pos != 0 ) + return Zstring(data, pos); //data is non-empty string in this context: else ch would not have been found! + else + return Zstring(); +} + + +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(const Zstring& begin) const +{ + const size_t beginLength = begin.length(); + if (length() < beginLength) + return false; + return compare(0, beginLength, begin) == 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 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) == 0; +} + + +inline +size_t Zstring::find(const defaultChar* str, const size_t pos) const +{ + assert(pos <= length()); + const defaultChar* thisStr = c_str(); + const defaultChar* found = defaultStrFind(thisStr + pos, str); + return found == NULL ? npos : found - thisStr; +} + + +inline +size_t Zstring::find(const defaultChar ch, const 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 +Zstring::operator const wxString() const +{ + return wxString(c_str()); +} + + +inline +int Zstring::Cmp(const defaultChar* other) const +{ + return compare(other); +} + + +inline +int Zstring::Cmp(const Zstring& other) const +{ + return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest! +} + + +inline +bool Zstring::operator==(const Zstring& other) const +{ + return defaultCompare(c_str(), other.c_str()) == 0; //overload using strcmp(char*, char*) should be fastest! +} + + +inline +bool Zstring::operator==(const defaultChar* other) const +{ + return compare(other) == 0; +} + + +inline +int Zstring::compare(const Zstring& other) const +{ + return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest! +} + + +inline +int Zstring::compare(const defaultChar* other) const +{ + return defaultCompare(c_str(), other); //overload using strcmp(char*, char*) should be fastest! +} + + +inline +int Zstring::compare(const size_t pos1, const size_t n1, const defaultChar* other) const +{ + assert(length() - pos1 >= n1); + return defaultCompare(c_str() + pos1, other, n1); +} + + +inline +size_t Zstring::length() const +{ + return descr->length; +} + + +inline +const defaultChar* Zstring::c_str() const +{ + if (length()) + return data; + else +#ifdef ZSTRING_CHAR + return ""; +#elif defined ZSTRING_WIDE_CHAR + return L""; +#endif +} + + +inline +bool Zstring::empty() const +{ + return length() == 0; +} + + +inline +Zstring Zstring::operator+(const Zstring& string2) const +{ + return Zstring(*this)+=string2; +} + + +inline +Zstring Zstring::operator+(const defaultChar* string2) const +{ + return Zstring(*this)+=string2; +} + + +inline +Zstring Zstring::operator+(const defaultChar ch) const +{ + return Zstring(*this)+=ch; +} + + +#endif // ZSTRING_H_INCLUDED diff --git a/synchronization.cpp b/synchronization.cpp index 9d9fd4d2..85b4d4c1 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -13,7 +13,12 @@ using namespace FreeFileSync; SyncProcess::SyncProcess(bool useRecycler, bool lineBreakOnMessages, StatusHandler* handler) : useRecycleBin(useRecycler), - statusUpdater(handler) + statusUpdater(handler), + txtCopyingFile(_("Copying file \"%x\" to \"%y\"")), + txtOverwritingFile(_("Copying file \"%x\" overwriting \"%y\"")), + txtCreatingFolder(_("Creating folder \"%x\"")), + txtDeletingFile(_("Deleting file \"%x\"")), + txtDeletingFolder(_("Deleting folder \"%x\"")) { if (lineBreakOnMessages) optionalLineBreak = wxT("\n"); @@ -138,12 +143,12 @@ void copyfileMultithreaded(const wxString& source, const wxString& target, Statu bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config) -{ //false if nothing was to be done - assert (statusUpdater); +{ //return false if nothing had to be done if (!cmpLine.selectedForSynchronization) return false; - wxString target; + Zstring statusText; + Zstring target; //synchronize file: switch (cmpLine.cmpResult) @@ -152,13 +157,19 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf switch (config.exLeftSideOnly) { case SyncConfiguration::SYNC_DIR_LEFT: //delete files on left - statusUpdater->updateStatusText(wxString(_("Deleting file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"")); + statusText = txtDeletingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); + statusUpdater->updateStatusText(statusText); + removeFile(cmpLine.fileDescrLeft.fullName, useRecycleBin); break; case SyncConfiguration::SYNC_DIR_RIGHT: //copy files to right target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName; - statusUpdater->updateStatusText(wxString(_("Copying file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") + - _(" to ") + optionalLineBreak + wxT("\"") + target + wxT("\"")); + + statusText = txtCopyingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); + statusText.Replace(wxT("%y"), target, false); + statusUpdater->updateStatusText(statusText); copyfileMultithreaded(cmpLine.fileDescrLeft.fullName, target, statusUpdater); break; @@ -174,13 +185,19 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf { case SyncConfiguration::SYNC_DIR_LEFT: //copy files to left target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName; - statusUpdater->updateStatusText(wxString(_("Copying file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") + - _(" to ") + optionalLineBreak + wxT("\"") + target + wxT("\"")); + + statusText = txtCopyingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); + statusText.Replace(wxT("%y"), target, false); + statusUpdater->updateStatusText(statusText); copyfileMultithreaded(cmpLine.fileDescrRight.fullName, target, statusUpdater); break; case SyncConfiguration::SYNC_DIR_RIGHT: //delete files on right - statusUpdater->updateStatusText(wxString(_("Deleting file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"")); + statusText = txtDeletingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); + statusUpdater->updateStatusText(statusText); + removeFile(cmpLine.fileDescrRight.fullName, useRecycleBin); break; case SyncConfiguration::SYNC_DIR_NONE: @@ -196,15 +213,19 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf switch (getSyncDirection(cmpLine.cmpResult, config)) { case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left - statusUpdater->updateStatusText(wxString(_("Copying file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") + - _(" overwriting ") + optionalLineBreak + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"")); + statusText = txtOverwritingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); + statusText.Replace(wxT("%y"), cmpLine.fileDescrLeft.fullName, false); + statusUpdater->updateStatusText(statusText); removeFile(cmpLine.fileDescrLeft.fullName, useRecycleBin); //only used if switch activated by user, else file is simply deleted copyfileMultithreaded(cmpLine.fileDescrRight.fullName, cmpLine.fileDescrLeft.fullName, statusUpdater); break; case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right - statusUpdater->updateStatusText(wxString(_("Copying file ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") + - _(" overwriting ") + optionalLineBreak + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"")); + statusText = txtOverwritingFile; + statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); + statusText.Replace(wxT("%y"), cmpLine.fileDescrRight.fullName, false); + statusUpdater->updateStatusText(statusText); removeFile(cmpLine.fileDescrRight.fullName, useRecycleBin); //only used if switch activated by user, else file is simply deleted copyfileMultithreaded(cmpLine.fileDescrLeft.fullName, cmpLine.fileDescrRight.fullName, statusUpdater); @@ -232,7 +253,8 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo if (!cmpLine.selectedForSynchronization) return false; - wxString target; + Zstring statusText; + Zstring target; //synchronize folders: switch (cmpLine.cmpResult) @@ -241,17 +263,24 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo switch (config.exLeftSideOnly) { case SyncConfiguration::SYNC_DIR_LEFT: //delete folders on left - statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"")); + statusText = txtDeletingFolder; + statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); + statusUpdater->updateStatusText(statusText); + removeDirectory(cmpLine.fileDescrLeft.fullName, useRecycleBin); break; case SyncConfiguration::SYNC_DIR_RIGHT: //create folders on right target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName; - statusUpdater->updateStatusText(wxString(_("Creating folder ")) + optionalLineBreak + wxT("\"") + target + wxT("\"")); - //some check to catch the error that directory on source has been deleted externally after the "compare"... + statusText = txtCreatingFolder; + statusText.Replace(wxT("%x"), target, false); + statusUpdater->updateStatusText(statusText); + + //some check to catch the error that directory on source has been deleted externally after "compare"... if (!wxDirExists(cmpLine.fileDescrLeft.fullName)) - throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"")); + throw FileError(wxString(_("Error: Source directory does not exist anymore:")) + wxT(" \"") + cmpLine.fileDescrLeft.fullName.c_str() + wxT("\"")); createDirectory(target); + copyFolderAttributes(cmpLine.fileDescrLeft.fullName, target); break; case SyncConfiguration::SYNC_DIR_NONE: return false; @@ -265,15 +294,22 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo { case SyncConfiguration::SYNC_DIR_LEFT: //create folders on left target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName; - statusUpdater->updateStatusText(wxString(_("Creating folder ")) + optionalLineBreak + wxT("\"") + target + wxT("\"")); - //some check to catch the error that directory on source has been deleted externally after the "compare"... + statusText = txtCreatingFolder; + statusText.Replace(wxT("%x"), target, false); + statusUpdater->updateStatusText(statusText); + + //some check to catch the error that directory on source has been deleted externally after "compare"... if (!wxDirExists(cmpLine.fileDescrRight.fullName)) - throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"")); + throw FileError(wxString(_("Error: Source directory does not exist anymore:")) + wxT(" \"") + cmpLine.fileDescrRight.fullName.c_str() + wxT("\"")); createDirectory(target); + copyFolderAttributes(cmpLine.fileDescrRight.fullName, target); break; case SyncConfiguration::SYNC_DIR_RIGHT: //delete folders on right - statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + optionalLineBreak + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"")); + statusText = txtDeletingFolder; + statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); + statusUpdater->updateStatusText(statusText); + removeDirectory(cmpLine.fileDescrRight.fullName, useRecycleBin); break; case SyncConfiguration::SYNC_DIR_NONE: @@ -386,7 +422,7 @@ void SyncProcess::startSynchronizationProcess(FileCompareResult& grid, const Syn //if (updateClass) -> is mandatory ErrorHandler::Response rv = statusUpdater->reportError(error.show()); - if ( rv == ErrorHandler::CONTINUE_NEXT) + if ( rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop @@ -443,7 +479,7 @@ void SyncProcess::startSynchronizationProcess(FileCompareResult& grid, const Syn //if (updateClass) -> is mandatory ErrorHandler::Response rv = statusUpdater->reportError(error.show()); - if ( rv == ErrorHandler::CONTINUE_NEXT) + if ( rv == ErrorHandler::IGNORE_ERROR) break; else if (rv == ErrorHandler::RETRY) ; //continue with loop @@ -480,12 +516,12 @@ public: wxString errorMessage; private: - void longRunner() //virtual method implementation + virtual void longRunner() //virtual method implementation { if (!wxCopyFile(source, target, false)) //abort if file exists { success = false; - errorMessage = wxString(_("Error copying file ")) + wxT("\"") + source + wxT("\"") + _(" to ") + wxT("\"") + target + wxT("\""); + errorMessage = wxString(_("Error copying file:")) + wxT(" \"") + source + wxT("\" -> \"") + target + wxT("\""); return; } @@ -494,7 +530,7 @@ private: if (stat(source.c_str(), &fileInfo) != 0) //read modification time from source file { success = false; - errorMessage = wxString(_("Could not retrieve file info for: ")) + wxT("\"") + source + wxT("\""); + errorMessage = wxString(_("Could not retrieve file info for:")) + wxT(" \"") + source + wxT("\""); return; } @@ -505,7 +541,7 @@ private: if (utime(target.c_str(), &newTimes) != 0) { success = false; - errorMessage = wxString(_("Error adapting modification time of file ")) + wxT("\"") + target + wxT("\""); + errorMessage = wxString(_("Error changing modification time:")) + wxT(" \"") + target + wxT("\""); return; } #endif // FFS_LINUX diff --git a/synchronization.h b/synchronization.h index 7bd3d216..32ffaba6 100644 --- a/synchronization.h +++ b/synchronization.h @@ -2,6 +2,7 @@ #define SYNCHRONIZATION_H_INCLUDED #include "FreeFileSync.h" +#include "library/statusHandler.h" namespace FreeFileSync @@ -28,6 +29,13 @@ namespace FreeFileSync const bool useRecycleBin; StatusHandler* statusUpdater; wxString optionalLineBreak; //optional line break for status messages (used by GUI mode only) + + //preload status texts + const Zstring txtCopyingFile; + const Zstring txtOverwritingFile; + const Zstring txtCreatingFolder; + const Zstring txtDeletingFile; + const Zstring txtDeletingFolder; }; } diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp index 818eff1c..7c74454f 100644 --- a/ui/MainDialog.cpp +++ b/ui/MainDialog.cpp @@ -12,7 +12,7 @@ #include "../library/globalFunctions.h" #include <wx/wfstream.h> #include <wx/clipbrd.h> -#include <wx/file.h> +#include <wx/ffile.h> #include "../library/customGrid.h" #include <algorithm> #include "../library/sorting.h" @@ -25,10 +25,10 @@ using namespace globalFunctions; using namespace xmlAccess; -int leadingPanel = 0; +extern const wxGrid* leadGrid = NULL; MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings) : - GuiGenerated(frame), + MainDialogGenerated(frame), globalSettings(settings), programLanguage(language), filteringInitialized(false), @@ -82,7 +82,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale m_menuItem7->SetBitmap(*globalResource.bitmapBatchSmall); m_menuItemAdjustTimes->SetBitmap(*globalResource.bitmapClockSmall); - //small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) + //Workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build) m_menu1->Remove(m_menuItem10); m_menu1->Remove(m_menuItem11); m_menu1->Insert(0, m_menuItem10); @@ -107,39 +107,39 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale contextMenu = new wxMenu; //support for CTRL + C and DEL - m_gridLeft->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGrid1ButtonEvent), NULL, this); - m_gridRight->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGrid2ButtonEvent), NULL, this); - m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGrid3ButtonEvent), NULL, this); + m_gridLeft->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridLeftButtonEvent), NULL, this); + m_gridRight->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridRightButtonEvent), NULL, this); + m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridMiddleButtonEvent), NULL, this); //identify leading grid by keyboard input or scroll action - m_gridLeft->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(MainDialog::onGrid1access), NULL, this); - m_gridLeft->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGrid1access), NULL, this); - - m_gridRight->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(MainDialog::onGrid2access), NULL, this); - m_gridRight->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGrid2access), NULL, this); - - m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGrid3access), NULL, this); - m_gridMiddle->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGrid3access), NULL, this); - m_gridMiddle->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGrid3access), NULL, this); - m_gridMiddle->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGrid3access), NULL, this); + m_gridLeft->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + m_gridLeft->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGridLeftAccess), NULL, this); + + m_gridRight->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + m_gridRight->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGridRightAccess), NULL, this); + + m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxEventHandler(MainDialog::onGridMiddleAccess), NULL, this); + m_gridMiddle->Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(MainDialog::onGridMiddleAccess), NULL, this); + m_gridMiddle->Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(MainDialog::onGridMiddleAccess), NULL, this); + m_gridMiddle->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::onGridMiddleAccess), NULL, this); Connect(wxEVT_IDLE, wxEventHandler(MainDialog::OnIdleEvent), NULL, this); m_gridMiddle->GetGridWindow()->Connect(wxEVT_LEFT_UP, wxEventHandler(MainDialog::OnGrid3LeftMouseUp), NULL, this); @@ -148,8 +148,9 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale Connect(wxEVT_SIZE, wxEventHandler(MainDialog::onResizeMainWindow), NULL, this); Connect(wxEVT_MOVE, wxEventHandler(MainDialog::onResizeMainWindow), NULL, this); - wxString toolTip = wxString(_("Legend\n")) + - _("---------\n") + + const wxString header = _("Legend"); + wxString toolTip = header + wxT("\n") + + wxString().Pad(header.Len(), wxChar('-')) + wxT("\n") + _("<| file on left side only\n") + _("|> file on right side only\n") + _("<< left file is newer\n") + @@ -164,7 +165,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale m_gridRight->setScrollFriends(m_gridLeft, m_gridRight, m_gridMiddle); m_gridMiddle->setScrollFriends(m_gridLeft, m_gridRight, m_gridMiddle); - //share UI grid data with grids + //share data with GUI grids m_gridLeft->setGridDataTable(&gridRefUI, ¤tGridData); m_gridRight->setGridDataTable(&gridRefUI, ¤tGridData); m_gridMiddle->setGridDataTable(&gridRefUI, ¤tGridData); @@ -177,7 +178,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale cellAttributes->SetAlignment(wxALIGN_RIGHT,wxALIGN_CENTRE); m_gridLeft->SetColAttr(2, cellAttributes); - cellAttributes = m_gridRight->GetOrCreateCellAttr(0, 2); //leave these two rows, might be necessary 'cause wxGridCellAttr is ref-counting + cellAttributes = m_gridRight->GetOrCreateCellAttr(0, 2); //leave these two rows, might be necessary 'cause wxGridCellAttr is ref-counting cellAttributes->SetAlignment(wxALIGN_RIGHT,wxALIGN_CENTRE); //and SetColAttr takes ownership (means: it will call DecRef()) m_gridRight->SetColAttr(2, cellAttributes); @@ -218,6 +219,9 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale case wxLANGUAGE_DUTCH: m_menuItemDutch->Check(); break; + case wxLANGUAGE_CHINESE_SIMPLIFIED: + m_menuItemChineseSimple->Check(); + break; default: m_menuItemEnglish->Check(); } @@ -234,10 +238,6 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale int spaceToAdd = source.GetX() - target.GetX(); bSizerMiddle->Insert(1, spaceToAdd / 2, 0, 0); bSizerMiddle->Insert(0, spaceToAdd - (spaceToAdd / 2), 0, 0); - - //adjust folder pair buttons - if (additionalFolderPairs.size() <= 0) - m_bpButtonRemovePair->Disable(); } @@ -306,18 +306,35 @@ void MainDialog::readGlobalSettings() for (int i = 0; i < m_gridRight->GetNumberCols() && i < int(globalSettings.gui.columnWidthRight.size()); ++i) m_gridRight->SetColSize(i, globalSettings.gui.columnWidthRight[i]); + +/* //read column positions + for (int i = 0; i < m_gridLeft->GetNumberCols() && i < int(globalSettings.gui.columnPositionsLeft.size()); ++i) + { + const int newPosition = globalSettings.gui.columnPositionsLeft[i]; + if (0 <= newPosition && newPosition < m_gridLeft->GetNumberCols()) + m_gridLeft->SetColPos(i, newPosition); + } + + for (int i = 0; i < m_gridRight->GetNumberCols() && i < int(globalSettings.gui.columnPositionsRight.size()); ++i) + { + const int newPosition = globalSettings.gui.columnPositionsRight[i]; + if (0 <= newPosition && newPosition < m_gridRight->GetNumberCols()) + m_gridRight->SetColPos(i, newPosition); + } + */ } void MainDialog::writeGlobalSettings() { //write global settings to (global) variable stored in application instance - globalSettings.gui.widthNotMaximized = widthNotMaximized; - globalSettings.gui.heightNotMaximized = heightNotMaximized; - globalSettings.gui.posXNotMaximized = posXNotMaximized; - globalSettings.gui.posYNotMaximized = posYNotMaximized; - globalSettings.gui.isMaximized = IsMaximized(); + globalSettings.gui.widthNotMaximized = widthNotMaximized; + globalSettings.gui.heightNotMaximized = heightNotMaximized; + globalSettings.gui.posXNotMaximized = posXNotMaximized; + globalSettings.gui.posYNotMaximized = posYNotMaximized; + globalSettings.gui.isMaximized = IsMaximized(); + //write column widths globalSettings.gui.columnWidthLeft.clear(); for (int i = 0; i < m_gridLeft->GetNumberCols(); ++i) globalSettings.gui.columnWidthLeft.push_back(m_gridLeft->GetColSize(i)); @@ -325,42 +342,52 @@ void MainDialog::writeGlobalSettings() globalSettings.gui.columnWidthRight.clear(); for (int i = 0; i < m_gridRight->GetNumberCols(); ++i) globalSettings.gui.columnWidthRight.push_back(m_gridRight->GetColSize(i)); + +/* + //write column positions + globalSettings.gui.columnPositionsLeft.clear(); + for (int i = 0; i < m_gridLeft->GetNumberCols(); ++i) + globalSettings.gui.columnPositionsLeft.push_back(m_gridLeft->GetColPos(i)); + + globalSettings.gui.columnPositionsRight.clear(); + for (int i = 0; i < m_gridRight->GetNumberCols(); ++i) + globalSettings.gui.columnPositionsRight.push_back(m_gridRight->GetColPos(i));*/ } -void MainDialog::onGrid1access(wxEvent& event) +void MainDialog::onGridLeftAccess(wxEvent& event) { - if (leadingPanel != 1) + if (leadGrid != m_gridLeft) { - leadingPanel = 1; + leadGrid = m_gridLeft; m_gridLeft->SetFocus(); - m_gridRight->ClearSelection(); //clear selection on grid2 + m_gridRight->ClearSelection(); } event.Skip(); } -void MainDialog::onGrid2access(wxEvent& event) +void MainDialog::onGridRightAccess(wxEvent& event) { - if (leadingPanel != 2) + if (leadGrid != m_gridRight) { - leadingPanel = 2; + leadGrid = m_gridRight; m_gridRight->SetFocus(); - m_gridLeft->ClearSelection(); //clear selection on grid1 + m_gridLeft->ClearSelection(); } event.Skip(); } -void MainDialog::onGrid3access(wxEvent& event) +void MainDialog::onGridMiddleAccess(wxEvent& event) { - if (leadingPanel != 3) + if (leadGrid != m_gridMiddle) { - leadingPanel = 3; - m_gridLeft->ClearSelection(); //clear selection on grid1 - m_gridRight->ClearSelection(); //clear selection on grid1 + leadGrid = m_gridMiddle; + m_gridLeft->ClearSelection(); + m_gridRight->ClearSelection(); } event.Skip(); } @@ -480,7 +507,8 @@ void MainDialog::OnIdleEvent(wxEvent& event) { //a mouse up event, but no mouse down! (e.g. when window is maximized and cursor is on grid3) filteringInitialized = false; - filterRangeTemp(getSelectedRows()); + if (leadGrid) + filterRangeTemp(getSelectedRows(leadGrid)); } } @@ -504,34 +532,19 @@ void MainDialog::OnIdleEvent(wxEvent& event) } -void MainDialog::copySelectionToClipboard(const set<int>& selectedRows, int selectedGrid) +void MainDialog::copySelectionToClipboard(const wxGrid* selectedGrid) { + const set<int> selectedRows = getSelectedRows(selectedGrid); if (selectedRows.size() > 0) { - wxGrid* grid = 0; - switch (selectedGrid) - { - case 1: - grid = m_gridLeft; - break; - case 2: - grid = m_gridRight; - break; - case 3: - grid = m_gridMiddle; - break; - default: - return; - } - wxString clipboardString; for (set<int>::iterator i = selectedRows.begin(); i != selectedRows.end(); ++i) { - for (int k = 0; k < grid->GetNumberCols(); ++k) + for (int k = 0; k < const_cast<wxGrid*>(selectedGrid)->GetNumberCols(); ++k) { - clipboardString+= grid->GetCellValue(*i, k); - if (k != grid->GetNumberCols() - 1) + clipboardString+= const_cast<wxGrid*>(selectedGrid)->GetCellValue(*i, k); + if (k != const_cast<wxGrid*>(selectedGrid)->GetNumberCols() - 1) clipboardString+= '\t'; } clipboardString+= '\n'; @@ -564,25 +577,8 @@ void removeInvalidRows(set<int>& rows, const int currentUI_Size) } -set<int> MainDialog::getSelectedRows() +set<int> MainDialog::getSelectedRows(const wxGrid* grid) { - wxGrid* grid = 0; - - switch (leadingPanel) - { - case 1: - grid = m_gridLeft; - break; - case 2: - grid = m_gridRight; - break; - case 3: - grid = m_gridMiddle; - break; - default: - return set<int>(); - } - set<int> output; int rowTop, rowBottom; //coords of selection @@ -595,7 +591,7 @@ set<int> MainDialog::getSelectedRows() if (!grid->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion { - for (int k = 0; k < grid->GetNumberRows(); ++k) + for (int k = 0; k < const_cast<wxGrid*>(grid)->GetNumberRows(); ++k) output.insert(k); } @@ -646,12 +642,12 @@ public: if (ignoreErrors) { unsolvedErrors = true; - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } bool ignoreNextErrors = false; wxString errorMessage = text + wxT("\n\n") + _("Information: If you ignore the error or abort a re-compare will be necessary!"); - ErrorDlg* errorDlg = new ErrorDlg(parent, errorMessage, ignoreNextErrors, 90); + ErrorDlg* errorDlg = new ErrorDlg(parent, errorMessage, ignoreNextErrors); int rv = errorDlg->ShowModal(); switch (rv) @@ -659,7 +655,7 @@ public: case ErrorDlg::BUTTON_IGNORE: ignoreErrors = ignoreNextErrors; unsolvedErrors = true; - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: @@ -671,7 +667,7 @@ public: assert (false); } - return ErrorHandler::CONTINUE_NEXT; //dummy return value + return ErrorHandler::IGNORE_ERROR; //dummy return value } private: @@ -703,10 +699,10 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI) const FileCompareLine& currentCmpLine = currentGridData[*i]; if (currentCmpLine.fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) - filesToDelete+= currentCmpLine.fileDescrLeft.fullName + wxT("\n"); + filesToDelete += (currentCmpLine.fileDescrLeft.fullName + wxT("\n")).c_str(); if (currentCmpLine.fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) - filesToDelete+= currentCmpLine.fileDescrRight.fullName + wxT("\n"); + filesToDelete += (currentCmpLine.fileDescrRight.fullName + wxT("\n")).c_str(); filesToDelete+= wxT("\n"); } @@ -749,30 +745,30 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI) } -void MainDialog::openWithFileBrowser(int rowNumber, int gridNr) +void MainDialog::openWithFileBrowser(int rowNumber, const wxGrid* grid) { #ifdef FFS_WIN - if (gridNr == 1) + if (grid == m_gridLeft) { - wxString command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()); //default + wxString command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()).c_str(); //default if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) { const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrLeft; if (fileDescr.objType != FileDescrLine::TYPE_NOTHING) - command = wxString(wxT("explorer /select,")) + fileDescr.fullName; + command = wxString(wxT("explorer /select,")) + fileDescr.fullName.c_str(); } wxExecute(command); } - else if (gridNr == 2) + else if (grid == m_gridRight) { - wxString command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue()); //default + wxString command = wxString(wxT("explorer ")) + FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue()).c_str(); //default if (0 <= rowNumber && rowNumber < int(gridRefUI.size())) { const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrRight; if (fileDescr.objType != FileDescrLine::TYPE_NOTHING) - command = wxString(wxT("explorer /select,")) + fileDescr.fullName; + command = wxString(wxT("explorer /select,")) + fileDescr.fullName.c_str(); } wxExecute(command); } @@ -827,43 +823,43 @@ void MainDialog::onResizeMainWindow(wxEvent& event) } -void MainDialog::onGrid1ButtonEvent(wxKeyEvent& event) +void MainDialog::onGridLeftButtonEvent(wxKeyEvent& event) { //CTRL + C || CTRL + INS if ( event.ControlDown() && event.GetKeyCode() == 67 || event.ControlDown() && event.GetKeyCode() == WXK_INSERT) - copySelectionToClipboard(getSelectedRows(), 1); + copySelectionToClipboard(m_gridLeft); else if (event.GetKeyCode() == WXK_DELETE) - deleteFilesOnGrid(getSelectedRows()); + deleteFilesOnGrid(getSelectedRows(m_gridLeft)); event.Skip(); } -void MainDialog::onGrid2ButtonEvent(wxKeyEvent& event) +void MainDialog::onGridRightButtonEvent(wxKeyEvent& event) { //CTRL + C || CTRL + INS if ( event.ControlDown() && event.GetKeyCode() == 67 || event.ControlDown() && event.GetKeyCode() == WXK_INSERT) - copySelectionToClipboard(getSelectedRows(), 2); + copySelectionToClipboard(m_gridRight); else if (event.GetKeyCode() == WXK_DELETE) - deleteFilesOnGrid(getSelectedRows()); + deleteFilesOnGrid(getSelectedRows(m_gridRight)); event.Skip(); } -void MainDialog::onGrid3ButtonEvent(wxKeyEvent& event) +void MainDialog::onGridMiddleButtonEvent(wxKeyEvent& event) { //CTRL + C || CTRL + INS if ( event.ControlDown() && event.GetKeyCode() == 67 || event.ControlDown() && event.GetKeyCode() == WXK_INSERT) - copySelectionToClipboard(getSelectedRows(), 3); + copySelectionToClipboard(m_gridMiddle); else if (event.GetKeyCode() == WXK_DELETE) - deleteFilesOnGrid(getSelectedRows()); + deleteFilesOnGrid(getSelectedRows(m_gridMiddle)); event.Skip(); } @@ -871,7 +867,10 @@ void MainDialog::onGrid3ButtonEvent(wxKeyEvent& event) void MainDialog::OnOpenContextMenu(wxGridEvent& event) { - set<int> selection = getSelectedRows(); + set<int> selection; + + if (leadGrid) + selection = getSelectedRows(leadGrid); exFilterCandidateExtension.Clear(); exFilterCandidateObj.clear(); @@ -893,20 +892,20 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event) //get list of relative file/dir-names into vectors FilterObject newFilterEntry; - if (leadingPanel == 1) + if (leadGrid == m_gridLeft) for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i) { const FileCompareLine& line = currentGridData[gridRefUI[*i]]; - newFilterEntry.relativeName = line.fileDescrLeft.relativeName; + newFilterEntry.relativeName = line.fileDescrLeft.relativeName.c_str(); newFilterEntry.type = line.fileDescrLeft.objType; if (!newFilterEntry.relativeName.IsEmpty()) exFilterCandidateObj.push_back(newFilterEntry); } - else if (leadingPanel == 2) + else if (leadGrid == m_gridRight) for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i) { const FileCompareLine& line = currentGridData[gridRefUI[*i]]; - newFilterEntry.relativeName = line.fileDescrRight.relativeName; + newFilterEntry.relativeName = line.fileDescrRight.relativeName.c_str(); newFilterEntry.type = line.fileDescrRight.objType; if (!newFilterEntry.relativeName.IsEmpty()) exFilterCandidateObj.push_back(newFilterEntry); @@ -919,14 +918,14 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event) if (filename.Find(wxChar('.')) != wxNOT_FOUND) //be careful: AfterLast will return the whole string if '.' is not found! { exFilterCandidateExtension = filename.AfterLast(wxChar('.')); - contextMenu->Append(CONTEXT_EXCLUDE_EXT, wxString(_("Add to exclude filter: ")) + wxT("*.") + exFilterCandidateExtension); + contextMenu->Append(CONTEXT_EXCLUDE_EXT, wxString(_("Add to exclude filter:")) + wxT(" ") + wxT("*.") + exFilterCandidateExtension); } } if (exFilterCandidateObj.size() == 1) - contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + exFilterCandidateObj[0].relativeName); + contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter:")) + wxT(" ") + exFilterCandidateObj[0].relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR)); else if (exFilterCandidateObj.size() > 1) - contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + _("<multiple selection>")); + contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter:")) + wxT(" ") + _("<multiple selection>")); } else contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily")); //this element should always be visible @@ -957,7 +956,7 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event) } #ifdef FFS_WIN - if ((leadingPanel == 1 || leadingPanel == 2) && selection.size() <= 1) + if ((leadGrid == m_gridLeft || leadGrid == m_gridRight) && selection.size() <= 1) contextMenu->Enable(CONTEXT_EXPLORER, true); else contextMenu->Enable(CONTEXT_EXPLORER, false); @@ -971,12 +970,14 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event) void MainDialog::onContextMenuSelection(wxCommandEvent& event) { - set<int> selection = getSelectedRows(); - int eventId = event.GetId(); if (eventId == CONTEXT_FILTER_TEMP) { - filterRangeTemp(selection); + if (leadGrid) + { + set<int> selection = getSelectedRows(leadGrid); + filterRangeTemp(selection); + } } else if (eventId == CONTEXT_EXCLUDE_EXT) { @@ -991,7 +992,14 @@ void MainDialog::onContextMenuSelection(wxCommandEvent& event) updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); FreeFileSync::filterCurrentGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + writeGrid(currentGridData); + if (hideFilteredElements) + { + m_gridLeft->ClearSelection(); + m_gridRight->ClearSelection(); + m_gridMiddle->ClearSelection(); + } } } else if (eventId == CONTEXT_EXCLUDE_OBJ) @@ -1019,32 +1027,58 @@ void MainDialog::onContextMenuSelection(wxCommandEvent& event) updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); FreeFileSync::filterCurrentGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + writeGrid(currentGridData); + if (hideFilteredElements) + { + m_gridLeft->ClearSelection(); + m_gridRight->ClearSelection(); + m_gridMiddle->ClearSelection(); + } } } else if (eventId == CONTEXT_CLIPBOARD) { - copySelectionToClipboard(selection, leadingPanel); + if (leadGrid) + copySelectionToClipboard(leadGrid); } else if (eventId == CONTEXT_EXPLORER) { - if (leadingPanel == 1 || leadingPanel == 2) + if (leadGrid == m_gridLeft || leadGrid == m_gridRight) { + set<int> selection = getSelectedRows(leadGrid); + if (selection.size() == 1) - openWithFileBrowser(*selection.begin(), leadingPanel); + openWithFileBrowser(*selection.begin(), leadGrid); else if (selection.size() == 0) - openWithFileBrowser(-1, leadingPanel); + openWithFileBrowser(-1, leadGrid); } } else if (eventId == CONTEXT_DELETE_FILES) { - deleteFilesOnGrid(selection); + if (leadGrid) + { + set<int> selection = getSelectedRows(leadGrid); + deleteFilesOnGrid(selection); + } } event.Skip(); } +void MainDialog::OnColumnMenuLeft(wxGridEvent& event) +{ + event.Skip(); +} + + +void MainDialog::OnColumnMenuRight(wxGridEvent& event) +{ + event.Skip(); +} + + void MainDialog::OnWriteDirManually(wxCommandEvent& event) { wxString newDir = FreeFileSync::getFormattedDirectoryName(event.GetString()); @@ -1274,11 +1308,11 @@ void MainDialog::OnSaveConfig(wxCommandEvent& event) if (wxFileExists(newFileName)) { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(wxT("\"")) + newFileName + wxT("\"") + _(" already exists. Overwrite?"), _("Warning") , wxOK | wxCANCEL); + wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) { - pushStatusInformation(_("Saved aborted!")); + pushStatusInformation(_("Save aborted!")); return; } } @@ -1337,9 +1371,9 @@ void MainDialog::loadConfiguration(const wxString& filename) if (!filename.IsEmpty()) { if (!wxFileExists(filename)) - wxMessageBox(wxString(_("The selected file does not exist: ")) + filename, _("Warning"), wxOK); + wxMessageBox(wxString(_("The selected file does not exist:")) + wxT(" \"") + filename + wxT("\""), _("Warning"), wxOK); else if (xmlAccess::getXmlType(filename) != XML_GUI_CONFIG) - wxMessageBox(_("The selected file does not contain a valid configuration!"), _("Warning"), wxOK); + wxMessageBox(wxString(_("The file does not contain a valid configuration:")) + wxT(" \"") + filename + wxT("\""), _("Warning"), wxOK); else { //clear grids currentGridData.clear(); @@ -1424,11 +1458,18 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program updateCompareButtons(); updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - //read folder pairs, but first: clear existing pairs: + //read folder pairs: + //clear existing pairs first + m_directoryLeft->SetValue(wxEmptyString); + m_dirPickerLeft->SetPath(wxEmptyString); + m_directoryRight->SetValue(wxEmptyString); + m_dirPickerRight->SetPath(wxEmptyString); + removeFolderPair(true); //set main folder pair - if (guiCfg.directoryPairs.size() > 0) + const unsigned int folderPairCount = guiCfg.directoryPairs.size(); + if (folderPairCount > 0) { vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin(); @@ -1445,6 +1486,11 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program //set additional pairs for (vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin() + 1; i != guiCfg.directoryPairs.end(); ++i) addFolderPair(i->leftDirectory, i->rightDirectory); + + //adjust folder pair buttons + const int additionalFolderCount = folderPairCount - 1; + if (additionalFolderCount <= 0) + m_bpButtonRemovePair->Disable(); } //read GUI layout (optional!) @@ -1717,13 +1763,13 @@ void MainDialog::getFolderPairs(vector<FolderPair>& output, bool formatted) FolderPair newPair; if (formatted) { - newPair.leftDirectory = FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()); - newPair.rightDirectory = FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue()); + newPair.leftDirectory = FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()).c_str(); + newPair.rightDirectory = FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue()).c_str(); } else { - newPair.leftDirectory = m_directoryLeft->GetValue(); - newPair.rightDirectory = m_directoryRight->GetValue(); + newPair.leftDirectory = m_directoryLeft->GetValue().c_str(); + newPair.rightDirectory = m_directoryRight->GetValue().c_str(); } output.push_back(newPair); @@ -1738,8 +1784,8 @@ void MainDialog::getFolderPairs(vector<FolderPair>& output, bool formatted) } else { - newPair.leftDirectory = dirPair->m_directoryLeft->GetValue(); - newPair.rightDirectory = dirPair->m_directoryRight->GetValue(); + newPair.leftDirectory = dirPair->m_directoryLeft->GetValue().c_str(); + newPair.rightDirectory = dirPair->m_directoryRight->GetValue().c_str(); } output.push_back(newPair); @@ -1783,7 +1829,7 @@ void MainDialog::OnCompare(wxCommandEvent &event) clearStatusBar(); - wxBeginBusyCursor(); + wxBusyCursor dummy; //show hourglass cursor bool aborted = false; try @@ -1853,7 +1899,6 @@ void MainDialog::OnCompare(wxCommandEvent &event) m_gridRight->setSortMarker(-1); } - wxEndBusyCursor(); event.Skip(); } @@ -1914,12 +1959,12 @@ void MainDialog::OnSync(wxCommandEvent& event) cfg.syncConfiguration); if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0) { - wxMessageBox(_("Nothing to synchronize. Both directories adhere to the sync-configuration!"), _("Information"), wxICON_WARNING); + wxMessageBox(_("Nothing to synchronize according to configuration!"), _("Information"), wxICON_WARNING); return; } - wxBeginBusyCursor(); + wxBusyCursor dummy; //show hourglass cursor clearStatusBar(); try @@ -1946,8 +1991,6 @@ void MainDialog::OnSync(wxCommandEvent& event) pushStatusInformation(_("All items have been synchronized!")); enableSynchronization(false); } - - wxEndBusyCursor(); } event.Skip(); } @@ -1955,14 +1998,14 @@ void MainDialog::OnSync(wxCommandEvent& event) void MainDialog::OnLeftGridDoubleClick(wxGridEvent& event) { - openWithFileBrowser(event.GetRow(), 1); + openWithFileBrowser(event.GetRow(), m_gridLeft); event.Skip(); } void MainDialog::OnRightGridDoubleClick(wxGridEvent& event) { - openWithFileBrowser(event.GetRow(), 2); + openWithFileBrowser(event.GetRow(), m_gridRight); event.Skip(); } @@ -2123,14 +2166,17 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) //show status information on "root" level. if (foldersOnLeftView) { - wxString folderCount = numberToWxString(foldersOnLeftView); - globalFunctions::includeNumberSeparator(folderCount); - - statusLeftNew+= folderCount; if (foldersOnLeftView == 1) - statusLeftNew+= _(" directory"); + statusLeftNew+= _("1 directory"); else - statusLeftNew+= _(" directories"); + { + wxString folderCount = numberToWxString(foldersOnLeftView); + globalFunctions::includeNumberSeparator(folderCount); + + wxString outputString = _("%x directories"); + outputString.Replace(wxT("%x"), folderCount, false); + statusLeftNew+= outputString; + } if (filesOnLeftView) statusLeftNew+= wxT(", "); @@ -2138,38 +2184,53 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) if (filesOnLeftView) { - wxString fileCount = numberToWxString(filesOnLeftView); - globalFunctions::includeNumberSeparator(fileCount); - - statusLeftNew+= fileCount; if (filesOnLeftView == 1) - statusLeftNew+= _(" file, "); + statusLeftNew+= _("1 file,"); else - statusLeftNew+= _(" files, "); + { + wxString fileCount = numberToWxString(filesOnLeftView); + globalFunctions::includeNumberSeparator(fileCount); + wxString outputString = _("%x files,"); + outputString.Replace(wxT("%x"), fileCount, false); + statusLeftNew+= outputString; + } + statusLeftNew+= wxT(" "); statusLeftNew+= FreeFileSync::formatFilesizeToShortString(filesizeLeftView); } - wxString objectsTotal = numberToWxString(currentGridData.size()); - globalFunctions::includeNumberSeparator(objectsTotal); wxString objectsView = numberToWxString(visibleGrid.size()); globalFunctions::includeNumberSeparator(objectsView); if (currentGridData.size() == 1) - statusMiddleNew = objectsView + _(" of ") + objectsTotal + _(" row in view"); + { + wxString outputString = _("%x of 1 row in view"); + outputString.Replace(wxT("%x"), objectsView, false); + statusMiddleNew = outputString; + } else - statusMiddleNew = objectsView + _(" of ") + objectsTotal + _(" rows in view"); + { + wxString objectsTotal = numberToWxString(currentGridData.size()); + globalFunctions::includeNumberSeparator(objectsTotal); + wxString outputString = _("%x of %y rows in view"); + outputString.Replace(wxT("%x"), objectsView, false); + outputString.Replace(wxT("%y"), objectsTotal, false); + statusMiddleNew = outputString; + } if (foldersOnRightView) { - wxString folderCount = numberToWxString(foldersOnRightView); - globalFunctions::includeNumberSeparator(folderCount); - - statusRightNew+= folderCount; if (foldersOnRightView == 1) - statusRightNew+= _(" directory"); + statusRightNew+= _("1 directory"); else - statusRightNew+= _(" directories"); + { + wxString folderCount = numberToWxString(foldersOnRightView); + globalFunctions::includeNumberSeparator(folderCount); + + wxString outputString = _("%x directories"); + outputString.Replace(wxT("%x"), folderCount, false); + statusRightNew+= outputString; + } if (filesOnRightView) statusRightNew+= wxT(", "); @@ -2177,15 +2238,19 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid) if (filesOnRightView) { - wxString fileCount = numberToWxString(filesOnRightView); - globalFunctions::includeNumberSeparator(fileCount); - - statusRightNew+= fileCount; if (filesOnRightView == 1) - statusRightNew+= _(" file, "); + statusRightNew+= _("1 file,"); else - statusRightNew+= _(" files, "); + { + wxString fileCount = numberToWxString(filesOnRightView); + globalFunctions::includeNumberSeparator(fileCount); + wxString outputString = _("%x files,"); + outputString.Replace(wxT("%x"), fileCount, false); + statusRightNew+= outputString; + } + + statusRightNew+= wxT(" "); statusRightNew+= FreeFileSync::formatFilesizeToShortString(filesizeRightView); } @@ -2290,8 +2355,6 @@ void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& file m_panel112->Hide(); bSizer3->Layout(); - - //sorting is expensive: do performance measurements before implementing here! } @@ -2320,7 +2383,7 @@ void MainDialog::addFolderPair(const wxString& leftDir, const wxString& rightDir //set size of scrolled window wxSize pairSize = newPair->GetSize(); - int additionalRows = additionalFolderPairs.size(); + const int additionalRows = additionalFolderPairs.size(); if (additionalRows <= 3) //up to 3 additional pairs shall be shown m_scrolledWindowFolderPairs->SetMinSize(wxSize( -1, pairSize.GetHeight() * additionalRows)); else //adjust scrollbars @@ -2375,7 +2438,7 @@ void MainDialog::removeFolderPair(bool removeAll) while (removeAll && additionalFolderPairs.size() > 0); //set size of scrolled window - int additionalRows = additionalFolderPairs.size(); + const int additionalRows = additionalFolderPairs.size(); if (additionalRows <= 3) //up to 3 additional pairs shall be shown m_scrolledWindowFolderPairs->SetMinSize(wxSize(-1, pairSize.GetHeight() * additionalRows)); //adjust scrollbars (do not put in else clause) @@ -2450,6 +2513,8 @@ CompareStatusHandler::CompareStatusHandler(MainDialog* dlg) : CompareStatusHandler::~CompareStatusHandler() { + updateUiNow(); //ui update before enabling buttons again: prevent strange behaviour of delayed button clicks + //reenable complete main dialog mainDialog->m_radioBtnSizeDate->Enable(); mainDialog->m_radioBtnContent->Enable(); @@ -2486,12 +2551,13 @@ CompareStatusHandler::~CompareStatusHandler() mainDialog->m_buttonAbort->Disable(); mainDialog->m_buttonAbort->Hide(); - mainDialog->m_bpButtonCompare->Enable(); + + mainDialog->m_bpButtonCompare->Enable(); //enable compare button mainDialog->m_bpButtonCompare->Show(); //hide status panel from main window mainDialog->compareStatus->Hide(); - updateUiNow(); + mainDialog->Layout(); mainDialog->Refresh(); } @@ -2534,20 +2600,20 @@ void CompareStatusHandler::updateProcessedData(int objectsProcessed, double data ErrorHandler::Response CompareStatusHandler::reportError(const wxString& text) { if (ignoreErrors) - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; mainDialog->compareStatus->updateStatusPanelNow(); bool ignoreNextErrors = false; - wxString errorMessage = text + wxT("\n\n") + _("Ignore this error, retry or abort comparison?"); - ErrorDlg* errorDlg = new ErrorDlg(mainDialog, errorMessage, ignoreNextErrors, 90); + wxString errorMessage = text + wxT("\n\n") + _("Ignore this error, retry or abort?"); + ErrorDlg* errorDlg = new ErrorDlg(mainDialog, errorMessage, ignoreNextErrors); int rv = errorDlg->ShowModal(); switch (rv) { case ErrorDlg::BUTTON_IGNORE: ignoreErrors = ignoreNextErrors; - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: @@ -2559,7 +2625,7 @@ ErrorHandler::Response CompareStatusHandler::reportError(const wxString& text) assert (false); } - return ErrorHandler::CONTINUE_NEXT; //dummy return value + return ErrorHandler::IGNORE_ERROR; //dummy return value } @@ -2593,7 +2659,9 @@ SyncStatusHandler::~SyncStatusHandler() wxString result; if (failedItems) { - result = wxString(_("Warning: Synchronization failed for ")) + numberToWxString(failedItems) + _(" item(s):\n\n"); + result = wxString(_("Warning: Synchronization failed for %x item(s):")) + wxT("\n\n"); + result.Replace(wxT("%x"), globalFunctions::numberToWxString(failedItems), false); + for (unsigned int j = 0; j < failedItems; ++j) result+= unhandledErrors[j] + wxT("\n"); result+= wxT("\n"); @@ -2602,13 +2670,13 @@ SyncStatusHandler::~SyncStatusHandler() //notify to syncStatusFrame that current process has ended if (abortRequested) { - result+= wxString(_("Synchronization aborted!")) + _(" You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); + result+= wxString(_("Synchronization aborted!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); syncStatusFrame->setStatusText_NoUpdate(result); syncStatusFrame->processHasFinished(SyncStatus::ABORTED); //enable okay and close events } else if (failedItems) { - result+= wxString(_("Synchronization completed with errors!")) + _(" You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); + result+= wxString(_("Synchronization completed with errors!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); syncStatusFrame->setStatusText_NoUpdate(result); syncStatusFrame->processHasFinished(SyncStatus::FINISHED_WITH_ERROR); } @@ -2649,14 +2717,14 @@ ErrorHandler::Response SyncStatusHandler::reportError(const wxString& text) if (ignoreErrors) { unhandledErrors.Add(text); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } syncStatusFrame->updateStatusDialogNow(); bool ignoreNextErrors = false; wxString errorMessage = text + wxT("\n\n") + _("Ignore this error, retry or abort synchronization?"); - ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, errorMessage, ignoreNextErrors, 80); + ErrorDlg* errorDlg = new ErrorDlg(syncStatusFrame, errorMessage, ignoreNextErrors); int rv = errorDlg->ShowModal(); switch (rv) @@ -2664,7 +2732,7 @@ ErrorHandler::Response SyncStatusHandler::reportError(const wxString& text) case ErrorDlg::BUTTON_IGNORE: ignoreErrors = ignoreNextErrors; unhandledErrors.Add(text); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: @@ -2675,7 +2743,7 @@ ErrorHandler::Response SyncStatusHandler::reportError(const wxString& text) } default: assert (false); - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } } @@ -2705,11 +2773,11 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) fileName = filePicker->GetPath(); if (wxFileExists(fileName)) { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(wxT("\"")) + fileName + wxT("\"") + _(" already exists. Overwrite?"), _("Warning") , wxOK | wxCANCEL); + wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + fileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) { - pushStatusInformation(_("Saved aborted!")); + pushStatusInformation(_("Save aborted!")); event.Skip(); return; } @@ -2722,27 +2790,26 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) for (int k = 0; k < m_gridLeft->GetNumberCols(); ++k) { exportString+= m_gridLeft->GetCellValue(i, k); - exportString+= '\t'; + exportString+= ';'; } for (int k = 0; k < m_gridMiddle->GetNumberCols(); ++k) { exportString+= m_gridMiddle->GetCellValue(i, k); - exportString+= '\t'; + exportString+= ';'; } for (int k = 0; k < m_gridRight->GetNumberCols(); ++k) { exportString+= m_gridRight->GetCellValue(i, k); if (k != m_gridRight->GetNumberCols() - 1) - exportString+= '\t'; + exportString+= ';'; } exportString+= '\n'; } //write export file - wxFile output(fileName, wxFile::write); - + wxFFile output(fileName.c_str(), wxT("w")); //don't write in binary mode if (output.IsOpened()) { output.Write(exportString); @@ -2750,7 +2817,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) } else { - wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Error writing file:")) + wxT(" \"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR); } } @@ -2842,3 +2909,13 @@ void MainDialog::OnMenuLangDutch(wxCommandEvent& event) Destroy(); event.Skip(); } + + +void MainDialog::OnMenuLangChineseSimp(wxCommandEvent& event) +{ + programLanguage->setLanguage(wxLANGUAGE_CHINESE_SIMPLIFIED); //language is a global attribute + restartOnExit = true; + Destroy(); + event.Skip(); +} + diff --git a/ui/MainDialog.h b/ui/MainDialog.h index 46151521..31214fe4 100644 --- a/ui/MainDialog.h +++ b/ui/MainDialog.h @@ -30,16 +30,17 @@ enum ContextItem CONTEXT_EXCLUDE_OBJ, CONTEXT_CLIPBOARD, CONTEXT_EXPLORER, - CONTEXT_DELETE_FILES + CONTEXT_DELETE_FILES, + CONTEXT_HIDE_COLUMN, + CONTEXT_SHOW_ALL_COLUMNS }; -extern int leadingPanel; //better keep this an int! event.GetEventObject() does NOT always return m_grid1, m_grid2, m_grid3! +extern const wxGrid* leadGrid; //point to grid that is in focus class CompareStatusHandler; class FileDropEvent; -class TiXmlElement; -class MainDialog : public GuiGenerated +class MainDialog : public MainDialogGenerated { friend class CompareStatusHandler; friend class FileDropEvent; @@ -71,10 +72,10 @@ private: void updateStatusInformation(const GridView& output); //context menu functions - set<int> getSelectedRows(); + set<int> getSelectedRows(const wxGrid* grid); void filterRangeTemp(const set<int>& rowsToFilterOnUI_View); - void copySelectionToClipboard(const set<int>& selectedRows, int selectedGrid); - void openWithFileBrowser(int rowNumber, int gridNr); + void copySelectionToClipboard(const wxGrid* selectedGrid); + void openWithFileBrowser(int rowNumber, const wxGrid* grid); void deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI); //work to be done in idle time @@ -85,14 +86,16 @@ private: void clearStatusBar(); //events - void onGrid1access(wxEvent& event); - void onGrid2access(wxEvent& event); - void onGrid3access(wxEvent& event); + void onGridLeftAccess( wxEvent& event); + void onGridRightAccess( wxEvent& event); + void onGridMiddleAccess(wxEvent& event); - void onGrid1ButtonEvent(wxKeyEvent& event); - void onGrid2ButtonEvent(wxKeyEvent& event); - void onGrid3ButtonEvent(wxKeyEvent& event); + void onGridLeftButtonEvent(wxKeyEvent& event); + void onGridRightButtonEvent(wxKeyEvent& event); + void onGridMiddleButtonEvent(wxKeyEvent& event); void OnOpenContextMenu(wxGridEvent& event); + void OnColumnMenuLeft(wxGridEvent& event); + void OnColumnMenuRight(wxGridEvent& event); void OnWriteDirManually(wxCommandEvent& event); void OnDirSelected(wxFileDirPickerEvent& event); @@ -151,6 +154,7 @@ private: void OnMenuLangFrench( wxCommandEvent& event); void OnMenuLangJapanese( wxCommandEvent& event); void OnMenuLangDutch( wxCommandEvent& event); + void OnMenuLangChineseSimp( wxCommandEvent& event); void enableSynchronization(bool value); diff --git a/ui/SmallDialogs.cpp b/ui/SmallDialogs.cpp index 3a2e239e..4c6d0d7b 100644 --- a/ui/SmallDialogs.cpp +++ b/ui/SmallDialogs.cpp @@ -15,7 +15,7 @@ AboutDlg::AboutDlg(wxWindow* window) : AboutDlgGenerated(window) m_bitmap13->SetBitmap(*globalResource.bitmapGPL); //build information - wxString build = wxString(wxT("(")) + _("Build: ") + __TDATE__; + wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE build+= wxT(" - Unicode"); #else @@ -199,7 +199,7 @@ void DeleteDialog::OnClose(wxCloseEvent& event) //######################################################################################## -ErrorDlg::ErrorDlg(wxWindow* parentWindow, const wxString messageText, bool& ignoreNextErrors, int dummy) : +ErrorDlg::ErrorDlg(wxWindow* parentWindow, const wxString messageText, bool& ignoreNextErrors) : ErrorDlgGenerated(parentWindow), ignoreErrors(ignoreNextErrors) { @@ -334,11 +334,11 @@ public: if (ignoreErrors) { unsolvedErrors = true; - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; } bool ignoreNextErrors = false; - ErrorDlg* errorDlg = new ErrorDlg(parent, text, ignoreNextErrors, 90); + ErrorDlg* errorDlg = new ErrorDlg(parent, text, ignoreNextErrors); int rv = errorDlg->ShowModal(); switch (rv) @@ -346,7 +346,7 @@ public: case ErrorDlg::BUTTON_IGNORE: ignoreErrors = ignoreNextErrors; unsolvedErrors = true; - return ErrorHandler::CONTINUE_NEXT; + return ErrorHandler::IGNORE_ERROR; case ErrorDlg::BUTTON_RETRY: return ErrorHandler::RETRY; case ErrorDlg::BUTTON_ABORT: @@ -356,9 +356,8 @@ public: } default: assert (false); + return ErrorHandler::IGNORE_ERROR; //dummy return value } - - return ErrorHandler::CONTINUE_NEXT; //dummy return value } private: @@ -375,13 +374,15 @@ void ModifyFilesDlg::OnApply(wxCommandEvent& event) if (!wxDirExists(parentDir)) { - wxMessageBox(wxString(_("Directory does not exist: ")) + wxT("\"") + parentDir + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(wxString(_("Directory does not exist:")) + wxT(" \"") + parentDir + wxT("\""), _("Error"), wxOK | wxICON_ERROR); return; } bool unsolvedErrorOccured = false; //if an error is skipped a re-compare will be necessary! try { + wxBusyCursor dummy; //show hourglass cursor + ModifyErrorHandler errorHandler(this, unsolvedErrorOccured); FreeFileSync::adjustModificationTimes(parentDir, timeToShift, &errorHandler); } @@ -394,6 +395,7 @@ void ModifyFilesDlg::OnApply(wxCommandEvent& event) wxMessageBox(_("Unresolved errors occured during operation!"), _("Information"), wxOK); else wxMessageBox(_("All file times have been adjusted successfully!"), _("Information"), wxOK); + EndModal(BUTTON_APPLY); } diff --git a/ui/SmallDialogs.h b/ui/SmallDialogs.h index c75a1b9a..06e6c407 100644 --- a/ui/SmallDialogs.h +++ b/ui/SmallDialogs.h @@ -2,6 +2,7 @@ #define SMALLDIALOGS_H_INCLUDED #include "../FreeFileSync.h" +#include "../library/statusHandler.h" #include "guiGenerated.h" #include <wx/stopwatch.h> @@ -74,7 +75,7 @@ private: class ErrorDlg : public ErrorDlgGenerated { public: - ErrorDlg(wxWindow* parentWindow, const wxString messageText, bool& ignoreNextErrors, int dummy); + ErrorDlg(wxWindow* parentWindow, const wxString messageText, bool& ignoreNextErrors); ~ErrorDlg(); enum diff --git a/ui/SyncDialog.cpp b/ui/SyncDialog.cpp index a26931fe..67ec27dc 100644 --- a/ui/SyncDialog.cpp +++ b/ui/SyncDialog.cpp @@ -564,7 +564,7 @@ void BatchDialog::OnCreateBatchJob(wxCommandEvent& event) fileName = filePicker->GetPath(); if (wxFileExists(fileName)) { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(wxT("\"")) + fileName + wxT("\"") + _(" already exists. Overwrite?"), _("Warning") , wxOK | wxCANCEL); + wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + fileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) return; @@ -599,8 +599,8 @@ bool BatchDialog::createBatchFile(const wxString& filename) for (unsigned int i = 0; i < localFolderPairs.size(); ++i) { FolderPair newPair; - newPair.leftDirectory = localFolderPairs[i]->m_directoryLeft->GetValue(); - newPair.rightDirectory = localFolderPairs[i]->m_directoryRight->GetValue(); + newPair.leftDirectory = localFolderPairs[i]->m_directoryLeft->GetValue().c_str(); + newPair.rightDirectory = localFolderPairs[i]->m_directoryRight->GetValue().c_str(); batchCfg.directoryPairs.push_back(newPair); } @@ -624,7 +624,7 @@ bool BatchDialog::createBatchFile(const wxString& filename) /* #ifdef FFS_WIN -#include <windows.h> +#include <wx/msw/wrapwin.h> //includes "windows.h" #include <shlobj.h> #endif // FFS_WIN diff --git a/ui/SyncDialog.h b/ui/SyncDialog.h index 036e9b6f..10f449c8 100644 --- a/ui/SyncDialog.h +++ b/ui/SyncDialog.h @@ -18,9 +18,9 @@ public: ~SyncDialog(); enum - { - BUTTON_START = 15 - }; + { + BUTTON_START = 15 + }; static void updateConfigIcons(wxBitmapButton* button1, wxBitmapButton* button2, diff --git a/ui/guiGenerated.cpp b/ui/guiGenerated.cpp index 9daaecb4..b55b50ed 100644 --- a/ui/guiGenerated.cpp +++ b/ui/guiGenerated.cpp @@ -11,7 +11,7 @@ /////////////////////////////////////////////////////////////////////////// -GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) +MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); @@ -58,6 +58,9 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit m_menuItemJapanese = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("日本語") ) , wxEmptyString, wxITEM_RADIO ); m_menu31->Append( m_menuItemJapanese ); + m_menuItemChineseSimple = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("简体中文") ) , wxEmptyString, wxITEM_RADIO ); + m_menu31->Append( m_menuItemChineseSimple ); + m_menu3->Append( -1, _("&Language"), m_menu31 ); m_menu3->AppendSeparator(); @@ -327,7 +330,7 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit m_gridLeft->SetColSize( 1, 118 ); m_gridLeft->SetColSize( 2, 67 ); m_gridLeft->SetColSize( 3, 113 ); - m_gridLeft->EnableDragColMove( false ); + m_gridLeft->EnableDragColMove( true ); m_gridLeft->EnableDragColSize( true ); m_gridLeft->SetColLabelSize( 20 ); m_gridLeft->SetColLabelValue( 0, _("Filename") ); @@ -408,7 +411,7 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit m_gridRight->SetColSize( 1, 118 ); m_gridRight->SetColSize( 2, 67 ); m_gridRight->SetColSize( 3, 113 ); - m_gridRight->EnableDragColMove( false ); + m_gridRight->EnableDragColMove( true ); m_gridRight->EnableDragColSize( true ); m_gridRight->SetColLabelSize( 20 ); m_gridRight->SetColLabelValue( 0, _("Filename") ); @@ -591,107 +594,113 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit this->Layout(); // Connect Events - this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GuiGenerated::OnClose ) ); - this->Connect( m_menuItem10->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompare ) ); - this->Connect( m_menuItem11->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnSync ) ); - this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuSaveConfig ) ); - this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLoadConfig ) ); - this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuQuit ) ); - this->Connect( m_menuItemGerman->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangGerman ) ); - this->Connect( m_menuItemEnglish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangEnglish ) ); - this->Connect( m_menuItemFrench->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangFrench ) ); - this->Connect( m_menuItemDutch->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangDutch ) ); - this->Connect( m_menuItemJapanese->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangJapanese ) ); - this->Connect( m_menuItem7->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuBatchJob ) ); - this->Connect( m_menuItemAdjustTimes->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuAdjustFileTimes ) ); - this->Connect( m_menuItem5->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuExportFileList ) ); - this->Connect( m_menuItem3->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuAbout ) ); - m_bpButtonCompare->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnCompare ), NULL, this ); - m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnAbortCompare ), NULL, this ); - m_radioBtnSizeDate->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompareByTimeSize ), NULL, this ); - m_radioBtnContent->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompareByContent ), NULL, this ); - m_bpButton14->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnShowHelpDialog ), NULL, this ); - m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnFilterButton ), NULL, this ); - m_hyperlinkCfgFilter->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( GuiGenerated::OnConfigureFilter ), NULL, this ); - m_checkBoxHideFilt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( GuiGenerated::OnHideFilteredButton ), NULL, this ); - m_bpButtonSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSync ), NULL, this ); - m_directoryLeft->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( GuiGenerated::OnWriteDirManually ), NULL, this ); - m_dirPickerLeft->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( GuiGenerated::OnDirSelected ), NULL, this ); - m_bpButtonSwap->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSwapDirs ), NULL, this ); - m_bpButtonRemovePair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRemoveFolderPair ), NULL, this ); - m_bpButtonAddPair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnAddFolderPair ), NULL, this ); - m_directoryRight->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( GuiGenerated::OnWriteDirManually ), NULL, this ); - m_dirPickerRight->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( GuiGenerated::OnDirSelected ), NULL, this ); - m_gridLeft->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( GuiGenerated::OnLeftGridDoubleClick ), NULL, this ); - m_gridLeft->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridLeft->Connect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( GuiGenerated::OnSortLeftGrid ), NULL, this ); - m_gridMiddle->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridRight->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( GuiGenerated::OnRightGridDoubleClick ), NULL, this ); - m_gridRight->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridRight->Connect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( GuiGenerated::OnSortRightGrid ), NULL, this ); - m_bpButton201->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSaveConfig ), NULL, this ); - m_choiceLoad->Connect( wxEVT_CHAR, wxKeyEventHandler( GuiGenerated::OnChoiceKeyEvent ), NULL, this ); - m_choiceLoad->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GuiGenerated::OnLoadConfig ), NULL, this ); - m_bpButtonLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnLeftOnlyFiles ), NULL, this ); - m_bpButtonLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnLeftNewerFiles ), NULL, this ); - m_bpButtonEqual->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnEqualFiles ), NULL, this ); - m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnDifferentFiles ), NULL, this ); - m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRightNewerFiles ), NULL, this ); - m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRightOnlyFiles ), NULL, this ); - m_bpButton10->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnQuit ), NULL, this ); + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) ); + this->Connect( m_menuItem10->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) ); + this->Connect( m_menuItem11->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSync ) ); + this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuSaveConfig ) ); + this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLoadConfig ) ); + this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); + this->Connect( m_menuItemGerman->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangGerman ) ); + this->Connect( m_menuItemEnglish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangEnglish ) ); + this->Connect( m_menuItemFrench->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangFrench ) ); + this->Connect( m_menuItemDutch->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangDutch ) ); + this->Connect( m_menuItemJapanese->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangJapanese ) ); + this->Connect( m_menuItemChineseSimple->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangChineseSimp ) ); + this->Connect( m_menuItem7->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuBatchJob ) ); + this->Connect( m_menuItemAdjustTimes->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAdjustFileTimes ) ); + this->Connect( m_menuItem5->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuExportFileList ) ); + this->Connect( m_menuItem3->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) ); + m_bpButtonCompare->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this ); + m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAbortCompare ), NULL, this ); + m_radioBtnSizeDate->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompareByTimeSize ), NULL, this ); + m_radioBtnContent->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompareByContent ), NULL, this ); + m_bpButton14->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnShowHelpDialog ), NULL, this ); + m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); + m_hyperlinkCfgFilter->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); + m_checkBoxHideFilt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); + m_bpButtonSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); + m_directoryLeft->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_dirPickerLeft->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); + m_bpButtonSwap->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); + m_bpButtonRemovePair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRemoveFolderPair ), NULL, this ); + m_bpButtonAddPair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); + m_directoryRight->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_dirPickerRight->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); + m_gridLeft->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnLeftGridDoubleClick ), NULL, this ); + m_gridLeft->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridLeft->Connect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( MainDialogGenerated::OnSortLeftGrid ), NULL, this ); + m_gridLeft->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnColumnMenuLeft ), NULL, this ); + m_gridMiddle->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridRight->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnRightGridDoubleClick ), NULL, this ); + m_gridRight->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridRight->Connect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( MainDialogGenerated::OnSortRightGrid ), NULL, this ); + m_gridRight->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnColumnMenuRight ), NULL, this ); + m_bpButton201->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ), NULL, this ); + m_choiceLoad->Connect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnChoiceKeyEvent ), NULL, this ); + m_choiceLoad->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ), NULL, this ); + m_bpButtonLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftOnlyFiles ), NULL, this ); + m_bpButtonLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftNewerFiles ), NULL, this ); + m_bpButtonEqual->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnEqualFiles ), NULL, this ); + m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this ); + m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this ); + m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), NULL, this ); + m_bpButton10->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnQuit ), NULL, this ); } -GuiGenerated::~GuiGenerated() +MainDialogGenerated::~MainDialogGenerated() { // Disconnect Events - this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GuiGenerated::OnClose ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompare ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnSync ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuSaveConfig ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLoadConfig ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuQuit ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangGerman ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangEnglish ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangFrench ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangDutch ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangJapanese ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuBatchJob ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuAdjustFileTimes ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuExportFileList ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuAbout ) ); - m_bpButtonCompare->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnCompare ), NULL, this ); - m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnAbortCompare ), NULL, this ); - m_radioBtnSizeDate->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompareByTimeSize ), NULL, this ); - m_radioBtnContent->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( GuiGenerated::OnCompareByContent ), NULL, this ); - m_bpButton14->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnShowHelpDialog ), NULL, this ); - m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnFilterButton ), NULL, this ); - m_hyperlinkCfgFilter->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( GuiGenerated::OnConfigureFilter ), NULL, this ); - m_checkBoxHideFilt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( GuiGenerated::OnHideFilteredButton ), NULL, this ); - m_bpButtonSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSync ), NULL, this ); - m_directoryLeft->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( GuiGenerated::OnWriteDirManually ), NULL, this ); - m_dirPickerLeft->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( GuiGenerated::OnDirSelected ), NULL, this ); - m_bpButtonSwap->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSwapDirs ), NULL, this ); - m_bpButtonRemovePair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRemoveFolderPair ), NULL, this ); - m_bpButtonAddPair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnAddFolderPair ), NULL, this ); - m_directoryRight->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( GuiGenerated::OnWriteDirManually ), NULL, this ); - m_dirPickerRight->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( GuiGenerated::OnDirSelected ), NULL, this ); - m_gridLeft->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( GuiGenerated::OnLeftGridDoubleClick ), NULL, this ); - m_gridLeft->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridLeft->Disconnect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( GuiGenerated::OnSortLeftGrid ), NULL, this ); - m_gridMiddle->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridRight->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( GuiGenerated::OnRightGridDoubleClick ), NULL, this ); - m_gridRight->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( GuiGenerated::OnOpenContextMenu ), NULL, this ); - m_gridRight->Disconnect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( GuiGenerated::OnSortRightGrid ), NULL, this ); - m_bpButton201->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnSaveConfig ), NULL, this ); - m_choiceLoad->Disconnect( wxEVT_CHAR, wxKeyEventHandler( GuiGenerated::OnChoiceKeyEvent ), NULL, this ); - m_choiceLoad->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( GuiGenerated::OnLoadConfig ), NULL, this ); - m_bpButtonLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnLeftOnlyFiles ), NULL, this ); - m_bpButtonLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnLeftNewerFiles ), NULL, this ); - m_bpButtonEqual->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnEqualFiles ), NULL, this ); - m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnDifferentFiles ), NULL, this ); - m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRightNewerFiles ), NULL, this ); - m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnRightOnlyFiles ), NULL, this ); - m_bpButton10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( GuiGenerated::OnQuit ), NULL, this ); + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSync ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuSaveConfig ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLoadConfig ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangGerman ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangEnglish ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangFrench ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangDutch ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangJapanese ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLangChineseSimp ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuBatchJob ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAdjustFileTimes ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuExportFileList ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuAbout ) ); + m_bpButtonCompare->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnCompare ), NULL, this ); + m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAbortCompare ), NULL, this ); + m_radioBtnSizeDate->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompareByTimeSize ), NULL, this ); + m_radioBtnContent->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompareByContent ), NULL, this ); + m_bpButton14->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnShowHelpDialog ), NULL, this ); + m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); + m_hyperlinkCfgFilter->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); + m_checkBoxHideFilt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); + m_bpButtonSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); + m_directoryLeft->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_dirPickerLeft->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); + m_bpButtonSwap->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); + m_bpButtonRemovePair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRemoveFolderPair ), NULL, this ); + m_bpButtonAddPair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); + m_directoryRight->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( MainDialogGenerated::OnWriteDirManually ), NULL, this ); + m_dirPickerRight->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); + m_gridLeft->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnLeftGridDoubleClick ), NULL, this ); + m_gridLeft->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridLeft->Disconnect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( MainDialogGenerated::OnSortLeftGrid ), NULL, this ); + m_gridLeft->Disconnect( wxEVT_GRID_LABEL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnColumnMenuLeft ), NULL, this ); + m_gridMiddle->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridRight->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( MainDialogGenerated::OnRightGridDoubleClick ), NULL, this ); + m_gridRight->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnOpenContextMenu ), NULL, this ); + m_gridRight->Disconnect( wxEVT_GRID_LABEL_LEFT_CLICK, wxGridEventHandler( MainDialogGenerated::OnSortRightGrid ), NULL, this ); + m_gridRight->Disconnect( wxEVT_GRID_LABEL_RIGHT_CLICK, wxGridEventHandler( MainDialogGenerated::OnColumnMenuRight ), NULL, this ); + m_bpButton201->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ), NULL, this ); + m_choiceLoad->Disconnect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnChoiceKeyEvent ), NULL, this ); + m_choiceLoad->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ), NULL, this ); + m_bpButtonLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftOnlyFiles ), NULL, this ); + m_bpButtonLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLeftNewerFiles ), NULL, this ); + m_bpButtonEqual->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnEqualFiles ), NULL, this ); + m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this ); + m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this ); + m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), 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 ) @@ -1043,17 +1052,17 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS wxBoxSizer* bSizer68; bSizer68 = new wxBoxSizer( wxHORIZONTAL ); - m_button6 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); - m_button6->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - - bSizer68->Add( m_button6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_buttonCreate = new wxButton( this, wxID_ANY, _("&Create"), wxDefaultPosition, wxSize( 120,35 ), 0 ); m_buttonCreate->SetDefault(); m_buttonCreate->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); bSizer68->Add( m_buttonCreate, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_button6 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_button6->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer68->Add( m_button6, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer69->Add( bSizer68, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); bSizer54->Add( bSizer69, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); @@ -1075,8 +1084,8 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_bpButton7->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); m_bpButton8->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); m_bpButton9->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); - m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); m_buttonCreate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCreateBatchJob ), NULL, this ); + m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); } BatchDlgGenerated::~BatchDlgGenerated() @@ -1092,8 +1101,8 @@ BatchDlgGenerated::~BatchDlgGenerated() m_bpButton7->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); m_bpButton8->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); m_bpButton9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); - m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); m_buttonCreate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCreateBatchJob ), NULL, this ); + m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); } BatchFolderPairGenerated::BatchFolderPairGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) @@ -1852,7 +1861,7 @@ HelpDlgGenerated::HelpDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer70->Add( m_treeCtrl1, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); - m_staticText63 = new wxStaticText( m_scrolledWindow1, wxID_ANY, _("As a result 6 different status can be returned to categorize all files:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText63 = new wxStaticText( m_scrolledWindow1, wxID_ANY, _("As a result the files are separated into the following categories:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText63->Wrap( 500 ); bSizer70->Add( m_staticText63, 0, wxALL, 5 ); @@ -2042,7 +2051,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer72->Add( m_staticText54, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM, 5 ); wxFlexGridSizer* fgSizer9; - fgSizer9 = new wxFlexGridSizer( 2, 2, 5, 20 ); + fgSizer9 = new wxFlexGridSizer( 4, 2, 5, 20 ); fgSizer9->SetFlexibleDirection( wxBOTH ); fgSizer9->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); @@ -2070,7 +2079,15 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_staticText712->Wrap( -1 ); fgSizer9->Add( m_staticText712, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer72->Add( fgSizer9, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 ); + m_staticText91 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Misty Wu"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText91->Wrap( -1 ); + fgSizer9->Add( m_staticText91, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticText92 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("简体中文"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText92->Wrap( -1 ); + fgSizer9->Add( m_staticText92, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer72->Add( fgSizer9, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); m_scrolledWindow3->SetSizer( bSizer72 ); m_scrolledWindow3->Layout(); @@ -2309,17 +2326,17 @@ WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const bSizer25->Add( m_buttonResolve, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); - m_buttonAbort = new wxButton( this, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( -1,30 ), 0 ); - m_buttonAbort->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - - bSizer25->Add( m_buttonAbort, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); - m_buttonOK = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 ); m_buttonOK->SetDefault(); m_buttonOK->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); bSizer25->Add( m_buttonOK, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + m_buttonAbort = new wxButton( this, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonAbort->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer25->Add( m_buttonAbort, 0, wxTOP|wxBOTTOM|wxLEFT, 5 ); + bSizer25->Add( 5, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); @@ -2332,8 +2349,8 @@ WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( WarningDlgGenerated::OnClose ) ); m_buttonIgnore->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnIgnore ), NULL, this ); m_buttonResolve->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnResolve ), NULL, this ); - m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this ); m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnOkay ), NULL, this ); + m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this ); } WarningDlgGenerated::~WarningDlgGenerated() @@ -2342,8 +2359,8 @@ WarningDlgGenerated::~WarningDlgGenerated() this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( WarningDlgGenerated::OnClose ) ); m_buttonIgnore->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnIgnore ), NULL, this ); m_buttonResolve->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnResolve ), NULL, this ); - m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this ); m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnOkay ), NULL, this ); + m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), 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 ) @@ -2593,15 +2610,15 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer22->Add( 0, 0, 1, wxEXPAND, 5 ); - m_button17 = new wxButton( this, wxID_CANCEL, _("dummy"), wxDefaultPosition, wxSize( 0,0 ), 0 ); - bSizer22->Add( m_button17, 0, wxALIGN_BOTTOM, 5 ); - m_button10 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxSize( -1,30 ), 0 ); m_button10->SetDefault(); m_button10->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); bSizer22->Add( m_button10, 0, wxALL, 5 ); + m_button17 = new wxButton( this, wxID_CANCEL, _("dummy"), wxDefaultPosition, wxSize( 0,0 ), 0 ); + bSizer22->Add( m_button17, 0, wxALIGN_BOTTOM, 5 ); + bSizer21->Add( bSizer22, 0, wxEXPAND|wxTOP, 5 ); this->SetSizer( bSizer21 ); @@ -2614,8 +2631,8 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( FilterDlgGenerated::OnClose ) ); m_bpButtonHelp->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnHelp ), NULL, this ); m_button9->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnDefault ), NULL, this ); - m_button17->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this ); m_button10->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnOK ), NULL, this ); + m_button17->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this ); } FilterDlgGenerated::~FilterDlgGenerated() @@ -2624,8 +2641,8 @@ FilterDlgGenerated::~FilterDlgGenerated() this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( FilterDlgGenerated::OnClose ) ); m_bpButtonHelp->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnHelp ), NULL, this ); m_button9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnDefault ), NULL, this ); - m_button17->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this ); m_button10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnOK ), NULL, this ); + m_button17->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this ); } ModifyFilesDlgGenerated::ModifyFilesDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2690,7 +2707,7 @@ ModifyFilesDlgGenerated::ModifyFilesDlgGenerated( wxWindow* parent, wxWindowID i bSizer80->Add( 0, 5, 0, wxEXPAND, 5 ); wxStaticBoxSizer* sbSizer24; - sbSizer24 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Select folder") ), wxHORIZONTAL ); + sbSizer24 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Select a folder") ), wxHORIZONTAL ); m_textCtrlDirectory = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); sbSizer24->Add( m_textCtrlDirectory, 1, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); @@ -2711,17 +2728,17 @@ ModifyFilesDlgGenerated::ModifyFilesDlgGenerated( wxWindow* parent, wxWindowID i wxBoxSizer* bSizer83; bSizer83 = new wxBoxSizer( wxHORIZONTAL ); - m_button21 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); - m_button21->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - - bSizer83->Add( m_button21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_buttonApply = new wxButton( this, wxID_APPLY, _("Apply"), wxDefaultPosition, wxSize( -1,35 ), 0 ); m_buttonApply->SetDefault(); m_buttonApply->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); bSizer83->Add( m_buttonApply, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + m_button21 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_button21->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); + + bSizer83->Add( m_button21, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer80->Add( bSizer83, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); this->SetSizer( bSizer80 ); @@ -2732,8 +2749,8 @@ ModifyFilesDlgGenerated::ModifyFilesDlgGenerated( wxWindow* parent, wxWindowID i this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ModifyFilesDlgGenerated::OnClose ) ); m_textCtrlDirectory->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnWriteDirManually ), NULL, this ); m_dirPicker->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( ModifyFilesDlgGenerated::OnDirSelected ), NULL, this ); - m_button21->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnCancel ), NULL, this ); m_buttonApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnApply ), NULL, this ); + m_button21->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnCancel ), NULL, this ); } ModifyFilesDlgGenerated::~ModifyFilesDlgGenerated() @@ -2742,6 +2759,6 @@ ModifyFilesDlgGenerated::~ModifyFilesDlgGenerated() this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ModifyFilesDlgGenerated::OnClose ) ); m_textCtrlDirectory->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnWriteDirManually ), NULL, this ); m_dirPicker->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( ModifyFilesDlgGenerated::OnDirSelected ), NULL, this ); - m_button21->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnCancel ), NULL, this ); m_buttonApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnApply ), NULL, this ); + m_button21->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModifyFilesDlgGenerated::OnCancel ), NULL, this ); } diff --git a/ui/guiGenerated.h b/ui/guiGenerated.h index fd3e9c0f..d2c64166 100644 --- a/ui/guiGenerated.h +++ b/ui/guiGenerated.h @@ -49,9 +49,9 @@ class CustomGrid; /////////////////////////////////////////////////////////////////////////////// -/// Class GuiGenerated +/// Class MainDialogGenerated /////////////////////////////////////////////////////////////////////////////// -class GuiGenerated : public wxFrame +class MainDialogGenerated : public wxFrame { private: @@ -67,6 +67,7 @@ class GuiGenerated : public wxFrame wxMenuItem* m_menuItemFrench; wxMenuItem* m_menuItemDutch; wxMenuItem* m_menuItemJapanese; + wxMenuItem* m_menuItemChineseSimple; wxMenuItem* m_menuItem7; wxMenuItem* m_menuItemAdjustTimes; wxMenu* m_menu2; @@ -150,6 +151,7 @@ class GuiGenerated : public wxFrame virtual void OnMenuLangFrench( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangDutch( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLangJapanese( wxCommandEvent& event ){ event.Skip(); } + virtual void OnMenuLangChineseSimp( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuBatchJob( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuAdjustFileTimes( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuExportFileList( wxCommandEvent& event ){ event.Skip(); } @@ -169,8 +171,10 @@ class GuiGenerated : public wxFrame virtual void OnLeftGridDoubleClick( wxGridEvent& event ){ event.Skip(); } virtual void OnOpenContextMenu( wxGridEvent& event ){ event.Skip(); } virtual void OnSortLeftGrid( wxGridEvent& event ){ event.Skip(); } + virtual void OnColumnMenuLeft( wxGridEvent& event ){ event.Skip(); } virtual void OnRightGridDoubleClick( wxGridEvent& event ){ event.Skip(); } virtual void OnSortRightGrid( wxGridEvent& event ){ event.Skip(); } + virtual void OnColumnMenuRight( wxGridEvent& event ){ event.Skip(); } virtual void OnSaveConfig( wxCommandEvent& event ){ event.Skip(); } virtual void OnChoiceKeyEvent( wxKeyEvent& event ){ event.Skip(); } virtual void OnLoadConfig( wxCommandEvent& event ){ event.Skip(); } @@ -184,8 +188,8 @@ class GuiGenerated : public wxFrame public: - GuiGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("FreeFileSync - Folder Comparison and Synchronization"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 933,612 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); - ~GuiGenerated(); + MainDialogGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("FreeFileSync - Folder Comparison and Synchronization"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 933,612 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL ); + ~MainDialogGenerated(); }; @@ -267,8 +271,8 @@ class BatchDlgGenerated : public wxDialog wxStaticBitmap* m_bitmap17; wxBitmapButton* m_bpButton9; wxStaticLine* m_staticline9; - wxButton* m_button6; wxButton* m_buttonCreate; + wxButton* m_button6; // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } @@ -280,8 +284,8 @@ class BatchDlgGenerated : public wxDialog virtual void OnLeftNewer( wxCommandEvent& event ){ event.Skip(); } virtual void OnRightNewer( wxCommandEvent& event ){ event.Skip(); } virtual void OnDifferent( wxCommandEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } virtual void OnCreateBatchJob( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } public: @@ -546,6 +550,8 @@ class AboutDlgGenerated : public wxDialog wxStaticText* m_staticText71; wxStaticText* m_staticText711; wxStaticText* m_staticText712; + wxStaticText* m_staticText91; + wxStaticText* m_staticText92; wxStaticLine* m_staticline3; wxStaticText* m_staticText131; wxStaticBitmap* m_bitmap9; @@ -622,16 +628,16 @@ class WarningDlgGenerated : public wxDialog wxButton* m_buttonIgnore; wxButton* m_buttonResolve; - wxButton* m_buttonAbort; wxButton* m_buttonOK; + wxButton* m_buttonAbort; // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } virtual void OnIgnore( wxCommandEvent& event ){ event.Skip(); } virtual void OnResolve( wxCommandEvent& event ){ event.Skip(); } - virtual void OnAbort( wxCommandEvent& event ){ event.Skip(); } virtual void OnOkay( wxCommandEvent& event ){ event.Skip(); } + virtual void OnAbort( wxCommandEvent& event ){ event.Skip(); } public: @@ -706,15 +712,15 @@ class FilterDlgGenerated : public wxDialog wxButton* m_button9; - wxButton* m_button17; wxButton* m_button10; + 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 OnCancel( wxCommandEvent& event ){ event.Skip(); } virtual void OnOK( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } public: @@ -744,15 +750,15 @@ class ModifyFilesDlgGenerated : public wxDialog wxTextCtrl* m_textCtrlDirectory; wxDirPickerCtrl* m_dirPicker; wxSpinCtrl* m_spinCtrlTimeShift; - wxButton* m_button21; wxButton* m_buttonApply; + wxButton* m_button21; // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } virtual void OnWriteDirManually( wxCommandEvent& event ){ event.Skip(); } virtual void OnDirSelected( wxFileDirPickerEvent& event ){ event.Skip(); } - virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } virtual void OnApply( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } public: |