summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Application.cpp323
-rw-r--r--Application.h13
-rw-r--r--Changelog.txt16
-rw-r--r--FreeFileSync - Unicode.cbp47
-rw-r--r--FreeFileSync.cpp830
-rw-r--r--FreeFileSync.h214
-rw-r--r--Makefile_Win_ANSI.cmd32
-rw-r--r--Makefile_Win_Unicode.cmd6
-rw-r--r--Readme.txt2
-rw-r--r--Resources.datbin126988 -> 180418 bytes
-rw-r--r--dutch.lng596
-rw-r--r--french.lng94
-rw-r--r--german.lng58
-rw-r--r--japanese.lng88
-rw-r--r--library/CustomGrid.cpp27
-rw-r--r--library/CustomGrid.h2
-rw-r--r--library/globalFunctions.cpp76
-rw-r--r--library/globalFunctions.h49
-rw-r--r--library/misc.cpp58
-rw-r--r--library/misc.h9
-rw-r--r--library/multithreading.cpp6
-rw-r--r--library/multithreading.h52
-rw-r--r--library/processXml.cpp427
-rw-r--r--library/processXml.h115
-rw-r--r--library/resources.cpp21
-rw-r--r--library/resources.h19
-rw-r--r--library/sorting.h274
-rw-r--r--library/statusHandler.h76
-rw-r--r--library/wxWidgets.h19
-rw-r--r--ui/MainDialog.cpp882
-rw-r--r--ui/MainDialog.h42
-rw-r--r--ui/SmallDialogs.cpp200
-rw-r--r--ui/SmallDialogs.h41
-rw-r--r--ui/SyncDialog.cpp144
-rw-r--r--ui/guiGenerated.cpp231
-rw-r--r--ui/guiGenerated.h90
36 files changed, 3408 insertions, 1771 deletions
diff --git a/Application.cpp b/Application.cpp
index 32bbc132..c7a0beda 100644
--- a/Application.cpp
+++ b/Application.cpp
@@ -24,49 +24,71 @@ IMPLEMENT_APP(Application);
bool Application::ProcessIdle()
{
- static bool firstExecution = true;
- if (firstExecution)
+ static bool initialized = false;
+ if (!initialized)
{
- firstExecution = false;
+ initialized = true;
initialize(); //here the program initialization takes place
}
return wxApp::ProcessIdle();
}
//Note: initialization is done in the FIRST idle event instead of OnInit. Reason: Commandline mode requires the wxApp eventhandler to be established
-//for UI update events. This is not the case at the time of OnInit.
+//for UI update events. This is not the case at the time of OnInit().
bool Application::OnInit()
{
returnValue = 0;
- //do not call wxApp::OnInit() to avoid parsing commandline now, instead use own parser later
- return true;
-}
-
+ //do not call wxApp::OnInit() to avoid using default commandline parser
-void Application::initialize()
-{
//set working directory to current executable directory
if (!wxSetWorkingDirectory(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath()))
- throw RuntimeException(_("Could not set working directory to directory containing executable file!"));
+ { //show messagebox and quit program immediately
+ wxMessageBox(_("Could not set working directory to directory containing executable file!"), _("An exception occured!"), wxOK | wxICON_ERROR);
+ return false;
+ }
- globalResource.load(); //load image resources from file: must be called after working directory has been set
+ try //load global settings from XML: must be called AFTER working dir was set
+ {
+ globalSettings = xmlAccess::readGlobalSettings();
+ }
+ catch (const FileError& error)
+ {
+ if (wxFileExists(FreeFileSync::FfsGlobalSettingsFile))
+ { //show messagebox and quit program immediately
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
+ return false;
+ }
+ //else: globalSettings already has default values
+ }
- //set program language
- SetExitOnFrameDelete(false); //prevent messagebox from becoming top-level window
- programLanguage.loadLanguageFromCfg();
+ //set program language: needs to happen aber working directory has been set!
+ SetExitOnFrameDelete(false); //prevent error messagebox from becoming top-level window
+ programLanguage.setLanguage(globalSettings.global.programLanguage);
SetExitOnFrameDelete(true);
- //test if ffs is to be started on UI with config file passed as commandline parameter
- wxString configFileForUI = FreeFileSync::FfsLastConfigFile;
+ //load image resources from file: must be called after working directory has been set
+ globalResource.load();
+
+ return true;
+}
+
+
+void Application::initialize()
+{
+ //test if FFS is to be started on UI with config file passed as commandline parameter
if (argc > 1)
{
XmlType xmlConfigType = xmlAccess::getXmlType(argv[1]);
- if (xmlConfigType == XML_GUI_CONFIG)
- configFileForUI = argv[1];
+ if (xmlConfigType == XML_GUI_CONFIG) //start in GUI mode (configuration file specified)
+ {
+ MainDialog* frame = new MainDialog(NULL, argv[1], &programLanguage, globalSettings);
+ frame->SetIcon(*globalResource.programIcon); //set application icon
+ frame->Show();
+ }
else if (xmlConfigType == XML_BATCH_CONFIG) //start in commandline mode
{
- runBatchMode(argv[1]);
+ runBatchMode(argv[1], globalSettings);
if (applicationRunsInBatchWithoutWindows)
ExitMainLoop(); //exit programm on next main loop iteration
@@ -78,11 +100,18 @@ void Application::initialize()
return;
}
}
+ else //start in GUI mode (standard)
+ {
+ MainDialog* frame = new MainDialog(NULL, FreeFileSync::FfsLastConfigFile, &programLanguage, globalSettings);
+ frame->SetIcon(*globalResource.programIcon); //set application icon
+ frame->Show();
+ }
+}
+
- //start in GUI mode
- MainDialog* frame = new MainDialog(NULL, configFileForUI, &programLanguage);
- frame->SetIcon(*globalResource.programIcon); //set application icon
- frame->Show();
+bool Application::OnExceptionInMainLoop()
+{
+ throw; //just pass exceptions and avoid display of additional exception messagebox: they will be caught in OnRun()
}
@@ -92,17 +121,35 @@ int Application::OnRun()
{
wxApp::OnRun();
}
- catch (const RuntimeException& theException) //catch runtime errors during main event loop
+ catch (const RuntimeException& theException) //catch runtime errors during main event loop; wxApp::OnUnhandledException could be used alternatively
{
wxMessageBox(theException.show(), _("An exception occured!"), wxOK | wxICON_ERROR);
return -1;
}
+ catch (std::exception& e) //catch all STL exceptions
+ {
+ wxMessageBox(wxString::From8BitData(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR);
+ return -1;
+ }
+
return returnValue;
}
int Application::OnExit()
{
+ //get program language
+ globalSettings.global.programLanguage = programLanguage.getLanguage();
+
+ try //save global settings to XML
+ {
+ xmlAccess::writeGlobalSettings(globalSettings);
+ }
+ catch (const FileError& error)
+ {
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
+ }
+
return 0;
}
@@ -186,136 +233,122 @@ private:
};
-void Application::runBatchMode(const wxString& filename)
+void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSettings& globalSettings)
{
applicationRunsInBatchWithoutWindows = false; //default value
//load XML settings
- XmlInput inputFile(filename, XML_BATCH_CONFIG);
-
- if (!inputFile.loadedSuccessfully())
- { //handle error: file load
- wxMessageBox(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
+ XmlBatchConfig batchCfg; //structure to receive gui settings
+ try
+ {
+ batchCfg = xmlAccess::readBatchConfig(filename);
+ }
+ catch (const FileError& error)
+ {
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
return;
}
- XmlMainConfig mainCfg; //structure to receive main settings
- XmlBatchConfig batchCfg; //structure to receive batch settings
- if ( inputFile.readXmlMainConfig(mainCfg) && //read main configuration settings
- inputFile.readXmlBatchConfig(batchCfg)) //read GUI layout configuration
+ //all settings have been read successfully...
+ applicationRunsInBatchWithoutWindows = batchCfg.silent; //this value is needed for the application to decide whether to wait for windows to close or not
+
+ //format directory names
+ for (vector<FolderPair>::iterator i = batchCfg.directoryPairs.begin(); i != batchCfg.directoryPairs.end(); ++i)
{
- //all settings have been read successfully...
+ i->leftDirectory = FreeFileSync::getFormattedDirectoryName(i->leftDirectory);
+ i->rightDirectory = FreeFileSync::getFormattedDirectoryName(i->rightDirectory);
+ }
- applicationRunsInBatchWithoutWindows = batchCfg.silent; //this value is needed for the application to decide whether to wait for windows to close or not
+ //init logfile
+ LogFile* log = NULL;
+ if (batchCfg.silent)
+ log = new LogFile;
+ DeleteOnExit dummy(log); //delete log object on exit (if not NULL)
- //format directory names
- for (vector<FolderPair>::iterator i = mainCfg.directoryPairs.begin(); i != mainCfg.directoryPairs.end(); ++i)
- {
- i->leftDirectory = FreeFileSync::getFormattedDirectoryName(i->leftDirectory);
- i->rightDirectory = FreeFileSync::getFormattedDirectoryName(i->rightDirectory);
- }
+ if (log && !log->isOkay())
+ { //handle error: file load
+ wxMessageBox(_("Unable to create logfile!"), _("Error"), wxOK | wxICON_ERROR);
+ return;
+ }
- //init logfile
- LogFile* log = NULL;
- if (batchCfg.silent)
- log = new LogFile;
- DeleteOnExit dummy(log); //delete log object on exit (if not NULL)
- if (log && !log->isOkay())
- { //handle error: file load
- wxMessageBox(_("Unable to create logfile!"), _("Error"), wxOK | wxICON_ERROR);
- return;
+ //check if directories exist
+ wxString errorMessage;
+ if (!FreeFileSync::foldersAreValidForComparison(batchCfg.directoryPairs, errorMessage))
+ {
+ if (batchCfg.silent)
+ {
+ log->write(errorMessage, _("Warning"));
+ log->close(_("Synchronization aborted!"));
}
+ else wxMessageBox(errorMessage + wxT("\n\n") + _("Synchronization aborted!"), _("Warning"), wxICON_WARNING);
+
+ returnValue = -2;
+ return;
+ }
- //check if directories exist
- wxString errorMessage;
- if (!FreeFileSync::foldersAreValidForComparison(mainCfg.directoryPairs, errorMessage))
+ //test existence of Recycle Bin
+ if (batchCfg.mainCfg.useRecycleBin)
+ {
+ if (!FreeFileSync::recycleBinExists())
{
+ wxString errorMessage = wxString(_("Unable to initialize Recycle Bin!"));
+ wxString statusMessage = wxString(_("Synchronization aborted!"));
if (batchCfg.silent)
{
- log->write(errorMessage, _("Warning"));
- log->close(_("Synchronization aborted!"));
+ log->write(errorMessage, _("Error"));
+ log->close(statusMessage);
}
- else wxMessageBox(errorMessage + wxT("\n\n") + _("Synchronization aborted!"), _("Warning"), wxICON_WARNING);
+ else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Error"), wxICON_WARNING);
returnValue = -2;
return;
}
+ }
-
- //test existence of Recycle Bin
- if (mainCfg.cfg.useRecycleBin)
- {
- if (!FreeFileSync::recycleBinExists())
- {
- wxString errorMessage = wxString(_("Unable to initialize Recycle Bin!"));
- wxString statusMessage = wxString(_("Synchronization aborted!"));
- if (batchCfg.silent)
- {
- log->write(errorMessage, _("Error"));
- log->close(statusMessage);
- }
- else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Error"), wxICON_WARNING);
-
- returnValue = -2;
- return;
- }
- }
-
- //begin of synchronization process (all in one try-catch block)
- try
+ //begin of synchronization process (all in one try-catch block)
+ try
+ {
+ FileCompareResult currentGridData;
+ //class handling status updates and error messages
+ BatchStatusUpdater statusUpdater(batchCfg.mainCfg.continueOnError, batchCfg.silent, log);
+
+ //COMPARE DIRECTORIES
+ FreeFileSync::startCompareProcess(batchCfg.directoryPairs,
+ batchCfg.mainCfg.compareVar,
+ currentGridData,
+ &statusUpdater);
+
+ //APPLY FILTERS
+ if (batchCfg.mainCfg.filterIsActive)
+ FreeFileSync::filterCurrentGridData(currentGridData, batchCfg.mainCfg.includeFilter, batchCfg.mainCfg.excludeFilter);
+
+ //check if there are files/folders to be sync'ed at all
+ int objectsToCreate = 0;
+ int objectsToOverwrite = 0;
+ int objectsToDelete = 0;
+ double dataToProcess = 0;
+ FreeFileSync::calcTotalBytesToSync(objectsToCreate,
+ objectsToOverwrite,
+ objectsToDelete,
+ dataToProcess,
+ currentGridData,
+ batchCfg.mainCfg.syncConfiguration);
+ if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0)
{
- FileCompareResult currentGridData;
- //class handling status updates and error messages
- BatchStatusUpdater statusUpdater(mainCfg.cfg.continueOnError, batchCfg.silent, log);
-
-//COMPARE DIRECTORIES
- //unsigned int startTime = GetTickCount();
- FreeFileSync::startCompareProcess(currentGridData,
- mainCfg.directoryPairs,
- mainCfg.cfg.compareVar,
- &statusUpdater);
- //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime));
-
-//APPLY FILTERS
- if (mainCfg.cfg.filterIsActive)
- FreeFileSync::filterCurrentGridData(currentGridData, mainCfg.cfg.includeFilter, mainCfg.cfg.excludeFilter);
-
-//check if there are files/folders to be sync'ed at all
- int objectsToCreate = 0;
- int objectsToOverwrite = 0;
- int objectsToDelete = 0;
- double dataToProcess = 0;
- FreeFileSync::calcTotalBytesToSync(objectsToCreate,
- objectsToOverwrite,
- objectsToDelete,
- dataToProcess,
- currentGridData,
- mainCfg.cfg.syncConfiguration);
- if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0)
- {
- statusUpdater.noSynchronizationNeeded(); //inform about this special case
-
- returnValue = -3;
- return;
- }
+ statusUpdater.noSynchronizationNeeded(); //inform about this special case
-//START SYNCHRONIZATION
- //unsigned int startTime = GetTickCount();
- FreeFileSync::startSynchronizationProcess(currentGridData, mainCfg.cfg.syncConfiguration, &statusUpdater, mainCfg.cfg.useRecycleBin);
- //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime));
- }
- catch (AbortThisProcess& theException) //exit used by statusUpdater
- {
- returnValue = -4;
+ returnValue = -3;
return;
}
+ //START SYNCHRONIZATION
+ FreeFileSync::startSynchronizationProcess(currentGridData, batchCfg.mainCfg.syncConfiguration, &statusUpdater, batchCfg.mainCfg.useRecycleBin);
}
- else
- { //handle error: parsing
- wxMessageBox(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
+ catch (AbortThisProcess& theException) //exit used by statusUpdater
+ {
+ returnValue = -4;
return;
}
@@ -328,7 +361,7 @@ BatchStatusUpdater::BatchStatusUpdater(bool continueOnError, bool silent, LogFil
m_log(log),
continueErrors(continueOnError),
silentMode(silent),
- currentProcess(-1),
+ currentProcess(StatusHandler::PROCESS_NONE),
synchronizationNeeded(true)
{
if (!silentMode)
@@ -400,7 +433,7 @@ void BatchStatusUpdater::updateStatusText(const wxString& text)
{
if (silentMode)
{
- if (currentProcess == FreeFileSync::synchronizeFilesProcess)
+ if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING)
m_log->write(text, _("Info"));
}
else
@@ -408,22 +441,22 @@ void BatchStatusUpdater::updateStatusText(const wxString& text)
}
-void BatchStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID)
+void BatchStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, StatusHandler::Process processID)
{
currentProcess = processID;
if (!silentMode)
{
- if (currentProcess == FreeFileSync::scanningFilesProcess)
+ if (currentProcess == StatusHandler::PROCESS_SCANNING)
syncStatusFrame->setCurrentStatus(SyncStatus::SCANNING);
- else if (currentProcess == FreeFileSync::compareFileContentProcess)
+ else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT)
{
syncStatusFrame->resetGauge(objectsTotal, dataTotal);
syncStatusFrame->setCurrentStatus(SyncStatus::COMPARING);
}
- else if (currentProcess == FreeFileSync::synchronizeFilesProcess)
+ else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING)
{
syncStatusFrame->resetGauge(objectsTotal, dataTotal);
syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING);
@@ -438,38 +471,38 @@ void BatchStatusUpdater::updateProcessedData(int objectsProcessed, double dataPr
{
if (!silentMode)
{
- if (currentProcess == FreeFileSync::scanningFilesProcess)
+ if (currentProcess == StatusHandler::PROCESS_SCANNING)
syncStatusFrame->m_gauge1->Pulse();
- else if (currentProcess == FreeFileSync::compareFileContentProcess)
+ else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT)
syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed);
- else if (currentProcess == FreeFileSync::synchronizeFilesProcess)
+ else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING)
syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed);
else assert(false);
}
}
-int BatchStatusUpdater::reportError(const wxString& text)
+ErrorHandler::Response BatchStatusUpdater::reportError(const wxString& text)
{
if (silentMode) //write error message log and abort the complete session if necessary
{
unhandledErrors.Add(text);
m_log->write(text, _("Error"));
- if (continueErrors) // <- /|\ before return, the logfile is written!!!
- return StatusUpdater::continueNext;
+ if (continueErrors) // /|\ before return, the logfile is written!!!
+ return ErrorHandler::CONTINUE_NEXT;
else
{
abortionRequested = true;
throw AbortThisProcess();
}
}
- else //show dialog to user who can decide how to continue
+ else //show dialog to user who can decide how to continue
{
if (continueErrors) //this option can be set from commandline or by the user in the error dialog on UI
{
unhandledErrors.Add(text);
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
}
wxString errorMessage = text + _("\n\nContinue with next object, retry or abort synchronization?");
@@ -481,12 +514,12 @@ int BatchStatusUpdater::reportError(const wxString& text)
switch (rv)
{
- case ErrorDlg::continueButtonPressed:
+ case ErrorDlg::BUTTON_CONTINUE:
unhandledErrors.Add(text);
- return StatusUpdater::continueNext;
- case ErrorDlg::retryButtonPressed:
- return StatusUpdater::retry;
- case ErrorDlg::abortButtonPressed:
+ return ErrorHandler::CONTINUE_NEXT;
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+ case ErrorDlg::BUTTON_ABORT:
{
unhandledErrors.Add(text);
abortionRequested = true;
@@ -494,7 +527,7 @@ int BatchStatusUpdater::reportError(const wxString& text)
}
default:
assert (false);
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
}
}
}
diff --git a/Application.h b/Application.h
index e240a762..220c81a1 100644
--- a/Application.h
+++ b/Application.h
@@ -15,6 +15,7 @@
#include "FreeFileSync.h"
#include "ui/smallDialogs.h"
#include "library/misc.h"
+#include "library/processXml.h"
class Application : public wxApp
{
@@ -22,31 +23,33 @@ public:
bool OnInit();
int OnRun();
int OnExit();
+ bool OnExceptionInMainLoop();
void initialize();
bool ProcessIdle(); //virtual method!
private:
- void runBatchMode(const wxString& filename);
+ void runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSettings& globalSettings);
bool applicationRunsInBatchWithoutWindows;
CustomLocale programLanguage;
int returnValue;
+ xmlAccess::XmlGlobalSettings globalSettings; //settings used by GUI, batch mode or both
};
class LogFile;
-class BatchStatusUpdater : public StatusUpdater
+class BatchStatusUpdater : public StatusHandler
{
public:
BatchStatusUpdater(bool continueOnError, bool silent, LogFile* log);
~BatchStatusUpdater();
void updateStatusText(const wxString& text);
- void initNewProcess(int objectsTotal, double dataTotal, int processID);
+ void initNewProcess(int objectsTotal, double dataTotal, Process processID);
void updateProcessedData(int objectsProcessed, double dataProcessed);
- int reportError(const wxString& text);
+ ErrorHandler::Response reportError(const wxString& text);
void forceUiRefresh();
void noSynchronizationNeeded();
@@ -60,7 +63,7 @@ private:
bool silentMode;
wxArrayString unhandledErrors; //list of non-resolved errors
- int currentProcess;
+ Process currentProcess;
bool synchronizationNeeded;
};
diff --git a/Changelog.txt b/Changelog.txt
index abad5df7..0e64fbac 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,6 +1,22 @@
FreeFileSync
------------
+Changelog v1.12
+---------------
+Significantly improved speed of all sorting algorithms
+Keep sorting sequence when adding or removing rows
+'Sort by relative path' secondarily sorts by filename and respects folders
+Allow adding multiple files/folders to exclude filter via context menu
+Exclude full relative path instead of short filenames via context menu
+Fixed possible memory leak when cancelling compare
+New option to manually adjust file modification times (To be used e.g. for FAT32 volumes on DST switch)
+Handling of different types of configuration (GUI, batch, global)
+Enhanced exception handling
+Multiple GUI improvements
+Added Dutch translation
+Updated translation files
+
+
Changelog v1.11
---------------
Support for multiple folder pairs
diff --git a/FreeFileSync - Unicode.cbp b/FreeFileSync - Unicode.cbp
index 1197abe3..640c289f 100644
--- a/FreeFileSync - Unicode.cbp
+++ b/FreeFileSync - Unicode.cbp
@@ -15,10 +15,10 @@
<Compiler>
<Add option="-g" />
<Add option="-D__WXDEBUG__" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswud" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" />
</Compiler>
<ResourceCompiler>
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswud" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" />
</ResourceCompiler>
<Linker>
<Add library="libwxmsw28ud_adv.a" />
@@ -26,7 +26,6 @@
<Add library="libwxbase28ud.a" />
<Add library="libwxpngd.a" />
<Add library="libwxzlibd.a" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib" />
</Linker>
</Target>
<Target title="Release">
@@ -38,10 +37,10 @@
<Compiler>
<Add option="-O2" />
<Add option="-DNDEBUG" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswu" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
</Compiler>
<ResourceCompiler>
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswu" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
</ResourceCompiler>
<Linker>
<Add option="-s" />
@@ -50,7 +49,6 @@
<Add library="libwxbase28u.a" />
<Add library="libwxpng.a" />
<Add library="libwxzlib.a" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib" />
</Linker>
</Target>
<Target title="Unit Test">
@@ -65,7 +63,7 @@
<Add option="-D__WXDEBUG__" />
<Add directory="library\gtest" />
<Add directory="library\gtest\include" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswud" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" />
</Compiler>
<Linker>
<Add library="libwxmsw28ud_adv.a" />
@@ -73,7 +71,6 @@
<Add library="libwxbase28ud.a" />
<Add library="libwxpngd.a" />
<Add library="libwxzlibd.a" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib" />
</Linker>
</Target>
</Build>
@@ -87,11 +84,11 @@
<Add option="-DFFS_WIN" />
<Add option="-DwxUSE_UNICODE" />
<Add option="-DTIXML_USE_STL" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\include" />
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\contrib\include" />
+ <Add directory="C:\Programme\C++\wxWidgets\include" />
+ <Add directory="C:\Programme\C++\wxWidgets\contrib\include" />
</Compiler>
<ResourceCompiler>
- <Add directory="C:\Programme\CodeBlocks\wxWidgets\include" />
+ <Add directory="C:\Programme\C++\wxWidgets\include" />
</ResourceCompiler>
<Linker>
<Add option="-mthreads" />
@@ -108,6 +105,7 @@
<Add library="libcomctl32.a" />
<Add library="libwsock32.a" />
<Add library="libodbc32.a" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" />
</Linker>
<Unit filename="FreeFileSync.cpp" />
<Unit filename="FreeFileSync.h">
@@ -139,6 +137,9 @@
<Option target="Debug" />
<Option target="Release" />
</Unit>
+ <Unit filename="library\gtest\main.cpp">
+ <Option target="Unit Test" />
+ </Unit>
<Unit filename="library\gtest\src\gtest-death-test.cc">
<Option target="Unit Test" />
</Unit>
@@ -154,16 +155,19 @@
<Unit filename="library\gtest\src\gtest.cc">
<Option target="Unit Test" />
</Unit>
- <Unit filename="library\gtest\src\gtest_main.cc">
+ <Unit filename="library\gtest\unittest.h">
<Option target="Unit Test" />
</Unit>
<Unit filename="library\gtest\unittest1.cpp">
<Option target="Unit Test" />
</Unit>
- <Unit filename="library\misc.cpp">
- <Option target="Debug" />
- <Option target="Release" />
+ <Unit filename="library\gtest\unittest2.cpp">
+ <Option target="Unit Test" />
+ </Unit>
+ <Unit filename="library\gtest\unittest3.cpp">
+ <Option target="Unit Test" />
</Unit>
+ <Unit filename="library\misc.cpp" />
<Unit filename="library\misc.h">
<Option target="Debug" />
<Option target="Release" />
@@ -173,11 +177,6 @@
<Option target="Debug" />
<Option target="Release" />
</Unit>
- <Unit filename="library\pch.h">
- <Option weight="0" />
- <Option target="Debug" />
- <Option target="Release" />
- </Unit>
<Unit filename="library\processXml.cpp" />
<Unit filename="library\processXml.h">
<Option target="Debug" />
@@ -188,6 +187,14 @@
<Option target="Debug" />
<Option target="Release" />
</Unit>
+ <Unit filename="library\sorting.h">
+ <Option target="Debug" />
+ <Option target="Release" />
+ </Unit>
+ <Unit filename="library\statusHandler.h">
+ <Option target="Debug" />
+ <Option target="Release" />
+ </Unit>
<Unit filename="library\tinyxml\tinystr.cpp" />
<Unit filename="library\tinyxml\tinyxml.cpp" />
<Unit filename="library\tinyxml\tinyxmlerror.cpp" />
diff --git a/FreeFileSync.cpp b/FreeFileSync.cpp
index d0927ae8..d7f398df 100644
--- a/FreeFileSync.cpp
+++ b/FreeFileSync.cpp
@@ -19,7 +19,78 @@
using namespace globalFunctions;
-const wxString FreeFileSync::FfsLastConfigFile = wxT("LastRun.ffs_gui");
+
+MainConfiguration::MainConfiguration() :
+ compareVar(CMP_BY_TIME_SIZE),
+ filterIsActive(false), //do not filter by default
+ includeFilter(wxT("*")), //include all files/folders
+ excludeFilter(wxEmptyString), //exclude nothing
+ useRecycleBin(FreeFileSync::recycleBinExists()), //enable if OS supports it; else user will have to activate first and then get an error message
+ continueOnError(false)
+{}
+
+
+struct FileInfo
+{
+ wxULongLong fileSize; //unit: bytes!
+ wxString lastWriteTime;
+ wxULongLong lastWriteTimeRaw; //unit: seconds!
+};
+
+
+//some special file functions
+void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusHandler* updateClass = 0);
+void getFileInformation(FileInfo& output, const wxString& filename);
+
+
+//Note: the following lines are a performance optimization for deleting elements from a vector. It is incredibly faster to create a new
+//vector and leave specific elements out than to delete row by row and force recopying of most elements for each single deletion (linear vs quadratic runtime)
+template <class T>
+void removeRowsFromVector(vector<T>& grid, const set<int>& rowsToRemove)
+{
+ vector<T> temp;
+ int rowToSkip = -1; //keep it an INT!
+
+ set<int>::iterator rowToSkipIndex = rowsToRemove.begin();
+
+ if (rowToSkipIndex != rowsToRemove.end())
+ rowToSkip = *rowToSkipIndex;
+
+ for (int i = 0; i < int(grid.size()); ++i)
+ {
+ if (i != rowToSkip)
+ temp.push_back(grid[i]);
+ else
+ {
+ ++rowToSkipIndex;
+ if (rowToSkipIndex != rowsToRemove.end())
+ rowToSkip = *rowToSkipIndex;
+ }
+ }
+ grid.swap(temp);
+}
+
+
+class GetAllFilesFull : public wxDirTraverser
+{
+public:
+ GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, 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;
+ StatusHandler* statusUpdater;
+};
+
inline
wxString formatTime(unsigned int number)
@@ -46,7 +117,7 @@ wxString formatTime(unsigned int number)
}
-void FreeFileSync::getFileInformation(FileInfo& output, const wxString& filename)
+void getFileInformation(FileInfo& output, const wxString& filename)
{
#ifdef FFS_WIN
WIN32_FIND_DATA winFileInfo;
@@ -159,7 +230,7 @@ bool filesHaveSameContent(const wxString& filename1, const wxString& filename2)
}
-void FreeFileSync::generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusUpdater* updateClass)
+void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusHandler* updateClass)
{
assert (updateClass);
@@ -168,17 +239,17 @@ void FreeFileSync::generateFileAndFolderDescriptions(DirectoryDescrType& output,
output.clear();
//get all files and folders from directory (and subdirectories) + information
- GetAllFilesFull traverser(output, getFormattedDirectoryName(directory), updateClass);
+ GetAllFilesFull traverser(output, FreeFileSync::getFormattedDirectoryName(directory), updateClass);
wxDir dir(directory);
if (dir.Traverse(traverser) != (size_t)-1)
break; //traversed successfully
else
{
- int rv = updateClass->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + directory + wxT("\""));
- if (rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = updateClass->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + directory + wxT("\""));
+ if (rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -217,7 +288,7 @@ private:
};
-bool filesHaveSameContentMultithreaded(const wxString& filename1, const wxString& filename2, StatusUpdater* updateClass)
+bool filesHaveSameContentMultithreaded(const wxString& filename1, const wxString& filename2, StatusHandler* updateClass)
{
static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution
@@ -304,7 +375,7 @@ public:
delete i->directoryDesc;
}
- const DirectoryDescrType* getDirectoryDescription(const wxString& directory, StatusUpdater* statusUpdater)
+ const DirectoryDescrType* getDirectoryDescription(const wxString& directory, StatusHandler* statusUpdater)
{
DescrBufferLine bufferEntry;
bufferEntry.directoryName = directory;
@@ -319,9 +390,9 @@ public:
{
//entry not found; create new one
bufferEntry.directoryDesc = new DirectoryDescrType;
- FreeFileSync::generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, statusUpdater);
- buffer.insert(bufferEntry);
+ buffer.insert(bufferEntry); //exception safety: insert into buffer right after creation!
+ generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, statusUpdater); //exceptions may be thrown!
return bufferEntry.directoryDesc;
}
}
@@ -331,169 +402,92 @@ private:
};
-void FreeFileSync::startCompareProcess(FileCompareResult& output,
- const vector<FolderPair>& directoryPairsFormatted,
+void FreeFileSync::startCompareProcess(const vector<FolderPair>& directoryPairsFormatted,
const CompareVariant cmpVar,
- StatusUpdater* statusUpdater)
+ FileCompareResult& output,
+ StatusHandler* statusUpdater)
{
#ifndef __WXDEBUG__
- wxLogNull dummy; //hide wxWidgets log messages in release build
+ wxLogNull noWxLogs; //hide wxWidgets log messages in release build
#endif
-
assert (statusUpdater);
//################################################################################################################################################
- //inform about the total amount of data that will be processed from now on
- statusUpdater->initNewProcess(-1, 0, FreeFileSync::scanningFilesProcess); //it's not known how many files will be scanned => -1 objects
-
- FileCompareResult output_tmp; //write to output not before END of process!
- set<int> delayedContentCompare; //compare of file content happens AFTER finding corresponding files
- //in order to separate into two processes (needed by progress indicators)
-
- //buffer accesses to the same directories; useful when multiple folder pairs are used
- DirectoryDescrBuffer descriptionBuffer;
+ FileCompareResult output_tmp; //write to output not before END of process!
try
{
- //process one folder pair after each other
- for (vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
- {
- //unsigned int startTime = GetTickCount();
-
- //retrieve sets of files (with description data)
- const DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, statusUpdater);
- const DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, statusUpdater);
+ //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
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime));
- statusUpdater->forceUiRefresh();
+ //do basis scan: only result lines of type FILE_UNDEFINED need to be determined
+ FreeFileSync::performBaseComparison(directoryPairsFormatted,
+ output_tmp,
+ statusUpdater);
- FileCompareLine newline;
-
- //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())
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = FileDescrLine();
- newline.fileDescrRight.directory = pair->rightDirectory;
- newline.cmpResult = FILE_LEFT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
-
- for (DirectoryDescrType::iterator j = directoryRight->begin(); j != directoryRight->end(); ++j)
+ if (cmpVar == CMP_BY_TIME_SIZE)
+ {
+ for (FileCompareResult::iterator i = output_tmp.begin(); i != output_tmp.end(); ++i)
{
- 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->cmpResult == FILE_UNDEFINED)
{
- newline.fileDescrLeft = FileDescrLine();
- newline.fileDescrLeft.directory = pair->leftDirectory; //directory info is needed when creating new directories
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
- //find files that exist in left and right file model
- else
- { //objType != TYPE_NOTHING
- if (i->objType == TYPE_DIRECTORY && j->objType == TYPE_DIRECTORY)
+ //last write time may differ by up to 2 seconds (NTFS vs FAT32)
+ bool sameWriteTime;
+ if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw)
+ sameWriteTime = (i->fileDescrRight.lastWriteTimeRaw - i->fileDescrLeft.lastWriteTimeRaw <= 2);
+ else
+ sameWriteTime = (i->fileDescrLeft.lastWriteTimeRaw - i->fileDescrRight.lastWriteTimeRaw <= 2);
+
+ if (sameWriteTime)
{
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_EQUAL;
- output_tmp.push_back(newline);
- }
- //if we have a nameclash between a file and a directory: split into separate rows
- else if (i->objType != j->objType)
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = FileDescrLine();
- newline.fileDescrRight.directory = pair->rightDirectory;
- newline.cmpResult = FILE_LEFT_SIDE_ONLY;
- output_tmp.push_back(newline);
-
- newline.fileDescrLeft = FileDescrLine();
- newline.fileDescrLeft.directory = pair->leftDirectory;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
- else if (cmpVar == CMP_BY_TIME_SIZE)
- { //check files that exist in left and right model but have different properties
-
- //last write time may differ by up to 2 seconds (NTFS vs FAT32)
- bool sameWriteTime;
- if (i->lastWriteTimeRaw < j->lastWriteTimeRaw)
- sameWriteTime = (j->lastWriteTimeRaw - i->lastWriteTimeRaw <= 2);
- else
- sameWriteTime = (i->lastWriteTimeRaw - j->lastWriteTimeRaw <= 2);
-
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- if (sameWriteTime)
- {
- if (i->fileSize == j->fileSize)
- newline.cmpResult = FILE_EQUAL;
- else
- newline.cmpResult = FILE_DIFFERENT;
- }
+ if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize)
+ i->cmpResult = FILE_EQUAL;
else
- {
- if (i->lastWriteTimeRaw < j->lastWriteTimeRaw)
- newline.cmpResult = FILE_RIGHT_NEWER;
- else
- newline.cmpResult = FILE_LEFT_NEWER;
- }
- output_tmp.push_back(newline);
+ i->cmpResult = FILE_DIFFERENT;
}
- else if (cmpVar == CMP_BY_CONTENT)
- { //check files that exist in left and right model but have different content
-
- //check filesize first!
- if (i->fileSize == j->fileSize)
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_INVALID; //not yet determined
- output_tmp.push_back(newline);
-
- //compare by content is only needed if filesizes are the same
- delayedContentCompare.insert(output_tmp.size() - 1); //save index of row, to calculate cmpResult later
- }
+ else
+ {
+ if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw)
+ i->cmpResult = FILE_RIGHT_NEWER;
else
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_DIFFERENT;
- output_tmp.push_back(newline);
- }
+ i->cmpResult = FILE_LEFT_NEWER;
}
- else assert (false);
}
}
}
-
//################################################################################################################################################
+ else if (cmpVar == CMP_BY_CONTENT)
+ {
+ set<int> rowsToCompareBytewise; //compare of file content happens AFTER finding corresponding files
+ //in order to separate into two processes (scanning and comparing)
- //compare file contents and set value "cmpResult"
+ //pre-check: files have different content if they have a different filesize
+ for (FileCompareResult::iterator i = output_tmp.begin(); i != output_tmp.end(); ++i)
+ {
+ if (i->cmpResult == FILE_UNDEFINED)
+ {
+ if (i->fileDescrLeft.fileSize != i->fileDescrRight.fileSize)
+ i->cmpResult = FILE_DIFFERENT;
+ else
+ rowsToCompareBytewise.insert(i - output_tmp.begin());
+ }
+ }
- //unsigned int startTime3 = GetTickCount();
- if (cmpVar == CMP_BY_CONTENT)
- {
int objectsTotal = 0;
double dataTotal = 0;
- calcTotalDataForCompare(objectsTotal, dataTotal, output_tmp, delayedContentCompare);
+ calcTotalDataForCompare(objectsTotal, dataTotal, output_tmp, rowsToCompareBytewise);
- statusUpdater->initNewProcess(objectsTotal, dataTotal, FreeFileSync::compareFileContentProcess);
+ statusUpdater->initNewProcess(objectsTotal, dataTotal, StatusHandler::PROCESS_COMPARING_CONTENT);
set<int> rowsToDelete; //if errors occur during file access and user skips, these rows need to be deleted from result
- for (set<int>::iterator i = delayedContentCompare.begin(); i != delayedContentCompare.end(); ++i)
+ //compair files (that have same size) bytewise...
+ for (set<int>::iterator i = rowsToCompareBytewise.begin(); i != rowsToCompareBytewise.end(); ++i)
{
FileCompareLine& gridline = output_tmp[*i];
- statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + wxT("\"") + gridline.fileDescrLeft.relFilename + wxT("\""));
+ statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + wxT("\"") + gridline.fileDescrLeft.relativeName + wxT("\""));
//check files that exist in left and right model but have different content
while (true)
@@ -503,24 +497,23 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
try
{
- if (filesHaveSameContentMultithreaded(gridline.fileDescrLeft.filename, gridline.fileDescrRight.filename, statusUpdater))
+ if (filesHaveSameContentMultithreaded(gridline.fileDescrLeft.fullName, gridline.fileDescrRight.fullName, statusUpdater))
gridline.cmpResult = FILE_EQUAL;
else
gridline.cmpResult = FILE_DIFFERENT;
- statusUpdater->updateProcessedData(2, (gridline.fileDescrLeft.fileSize + gridline.fileDescrRight.fileSize).ToDouble());
+ statusUpdater->updateProcessedData(2, (gridline.fileDescrLeft.fileSize * 2).ToDouble());
break;
}
catch (FileError& error)
{
- //if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if (rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
+ if (rv == ErrorHandler::CONTINUE_NEXT)
{
rowsToDelete.insert(*i);
break;
}
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -532,7 +525,8 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
if (rowsToDelete.size() > 0)
removeRowsFromVector(output_tmp, rowsToDelete);
}
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3));
+ else assert(false);
+
statusUpdater->requestUiRefresh();
}
@@ -541,12 +535,99 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
wxMessageBox(theException.show(), _("An exception occured!"), wxOK | wxICON_ERROR);
return;
}
+ catch (std::bad_alloc& e)
+ {
+ wxMessageBox(wxString(_("System out of memory!")) + wxT(" ") + wxString::From8BitData(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR);
+ return;
+ }
- //only if everything was processed correctly output is written to!
+//only if everything was processed correctly output is written to!
output_tmp.swap(output);
}
+void FreeFileSync::performBaseComparison(const vector<FolderPair>& directoryPairsFormatted,
+ FileCompareResult& output,
+ StatusHandler* statusUpdater)
+{
+ //buffer accesses to the same directories; useful when multiple folder pairs are used
+ DirectoryDescrBuffer descriptionBuffer;
+
+ //process one folder pair after each other
+ for (vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
+ {
+ //retrieve sets of files (with description data)
+ const DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, statusUpdater);
+ const DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, statusUpdater);
+
+ statusUpdater->forceUiRefresh();
+ FileCompareLine newline;
+
+ //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())
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = FileDescrLine();
+ newline.fileDescrRight.directory = pair->rightDirectory;
+ newline.cmpResult = FILE_LEFT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+
+ for (DirectoryDescrType::iterator j = directoryRight->begin(); j != directoryRight->end(); ++j)
+ {
+ DirectoryDescrType::iterator i;
+
+ //find files/folders that exist in right file model but not in left model
+ if ((i = directoryLeft->find(*j)) == directoryLeft->end())
+ {
+ newline.fileDescrLeft = FileDescrLine();
+ newline.fileDescrLeft.directory = pair->leftDirectory; //directory info is needed when creating new directories
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+ //find files/folders that exist in left and right file model
+ else
+ { //files...
+ if (i->objType == FileDescrLine::TYPE_FILE && j->objType == FileDescrLine::TYPE_FILE)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_UNDEFINED; //not yet determined!
+ output.push_back(newline);
+ }
+ //directories...
+ else if (i->objType == FileDescrLine::TYPE_DIRECTORY && j->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_EQUAL;
+ output.push_back(newline);
+ }
+ //if we have a nameclash between a file and a directory: split into two separate rows
+ else if (i->objType != j->objType)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = FileDescrLine();
+ newline.fileDescrRight.directory = pair->rightDirectory;
+ newline.cmpResult = FILE_LEFT_SIDE_ONLY;
+ output.push_back(newline);
+
+ newline.fileDescrLeft = FileDescrLine();
+ newline.fileDescrLeft.directory = pair->leftDirectory;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+ else assert (false);
+ }
+ }
+ }
+ statusUpdater->requestUiRefresh();
+}
+
+
void FreeFileSync::swapGrids(FileCompareResult& grid)
{
FileDescrLine tmp;
@@ -571,7 +652,7 @@ void FreeFileSync::swapGrids(FileCompareResult& grid)
}
-GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusUpdater* updateClass)
+GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusHandler* updateClass)
: m_output(output), directory(dirThatIsSearched), statusUpdater(updateClass)
{
assert(updateClass);
@@ -581,23 +662,23 @@ GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsS
wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
{
- fileDescr.filename = filename;
- fileDescr.directory = directory;
- fileDescr.relFilename = filename.Mid(prefixLength, wxSTRING_MAXLEN);
+ fileDescr.fullName = filename;
+ fileDescr.directory = directory;
+ fileDescr.relativeName = filename.Mid(prefixLength, wxSTRING_MAXLEN);
while (true)
{
try
{
- FreeFileSync::getFileInformation(currentFileInfo, filename);
+ getFileInformation(currentFileInfo, filename);
break;
}
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
return wxDIR_CONTINUE;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -607,13 +688,13 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
fileDescr.fileSize = currentFileInfo.fileSize;
- fileDescr.objType = TYPE_FILE;
+ fileDescr.objType = FileDescrLine::TYPE_FILE;
m_output.insert(fileDescr);
//update UI/commandline status information
- statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + filename + wxT("\"")); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + filename + wxT("\"")); //NO performance issue at all
//add 1 element to the progress indicator
- statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
+ statusUpdater->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
statusUpdater->requestUiRefresh();
@@ -624,43 +705,24 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
wxDirTraverseResult GetAllFilesFull::OnDir(const wxString& dirname)
{
#ifdef FFS_WIN
- if (dirname.EndsWith(wxT("\\RECYCLER")) ||
+ if ( dirname.EndsWith(wxT("\\RECYCLER")) ||
dirname.EndsWith(wxT("\\System Volume Information")))
return wxDIR_IGNORE;
#endif // FFS_WIN
- fileDescr.filename = dirname;
- fileDescr.directory = directory;
- fileDescr.relFilename = dirname.Mid(prefixLength, wxSTRING_MAXLEN);
- while (true)
- {
- try
- {
- FreeFileSync::getFileInformation(currentFileInfo, dirname);
- break;
- }
- catch (FileError& error)
- {
- //if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
- return wxDIR_IGNORE;
- else if (rv == StatusUpdater::retry)
- ; //continue with loop
- else
- assert (false);
- }
- }
- fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
- fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
- fileDescr.fileSize = wxULongLong(0); //currentFileInfo.fileSize should be "0" as well, but just to be sure... currently used by getBytesToTransfer
- fileDescr.objType = TYPE_DIRECTORY;
+ fileDescr.fullName = dirname;
+ fileDescr.directory = directory;
+ fileDescr.relativeName = dirname.Mid(prefixLength, wxSTRING_MAXLEN);
+ 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 ")) + wxT("\"") + dirname + wxT("\"")); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + dirname + wxT("\"")); //NO performance issue at all
//add 1 element to the progress indicator
- statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
+ statusUpdater->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
statusUpdater->requestUiRefresh();
@@ -682,19 +744,19 @@ class GetAllFilesSimple : public wxDirTraverser
{
public:
GetAllFilesSimple(wxArrayString& files, wxArrayString& subDirectories) :
- allFiles(files),
- subdirs(subDirectories)
+ m_files(files),
+ m_dirs(subDirectories)
{}
wxDirTraverseResult OnDir(const wxString& dirname)
{
- subdirs.Add(dirname);
+ m_dirs.Add(dirname);
return wxDIR_CONTINUE;
}
wxDirTraverseResult OnFile(const wxString& filename)
{
- allFiles.Add(filename);
+ m_files.Add(filename);
return wxDIR_CONTINUE;
}
@@ -705,8 +767,8 @@ public:
}
private:
- wxArrayString& allFiles;
- wxArrayString& subdirs;
+ wxArrayString& m_files;
+ wxArrayString& m_dirs;
};
@@ -747,7 +809,7 @@ public:
fileOp.lpszProgressTitle = NULL;
if (SHFileOperation(&fileOp //pointer to an SHFILEOPSTRUCT structure that contains information the function needs to carry out
- ) != 0 || fileOp.fAnyOperationsAborted) throw FileError(wxString(_("Error moving file to recycle bin: ")) + wxT("\"") + filename + wxT("\""));
+ ) != 0 || fileOp.fAnyOperationsAborted) throw FileError(wxString(_("Error moving to recycle bin: ")) + wxT("\"") + filename + wxT("\""));
#endif // FFS_WIN
}
@@ -760,11 +822,11 @@ RecycleBin FreeFileSync::recycler;
inline
-void FreeFileSync::removeFile(const wxString& filename)
+void FreeFileSync::removeFile(const wxString& filename, const bool useRecycleBin)
{
if (!wxFileExists(filename)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinShouldBeUsed)
+ if (useRecycleBin)
{
recycler.moveToRecycleBin(filename);
return;
@@ -782,11 +844,11 @@ void FreeFileSync::removeFile(const wxString& filename)
}
-void FreeFileSync::removeDirectory(const wxString& directory)
+void FreeFileSync::removeDirectory(const wxString& directory, const bool useRecycleBin)
{
if (!wxDirExists(directory)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinShouldBeUsed)
+ if (useRecycleBin)
{
recycler.moveToRecycleBin(directory);
return;
@@ -805,7 +867,7 @@ void FreeFileSync::removeDirectory(const wxString& directory)
}
for (unsigned int j = 0; j < fileList.GetCount(); ++j)
- removeFile(fileList[j]);
+ removeFile(fileList[j], useRecycleBin);
dirList.Insert(directory, 0); //this directory will be deleted last
@@ -829,7 +891,7 @@ void FreeFileSync::createDirectory(const wxString& directory, int level)
if (wxDirExists(directory))
return;
- if (level == 50) //catch endless loop
+ if (level == 50) //catch endless loop
return;
//try to create directory
@@ -909,15 +971,10 @@ private:
success = true;
}
-
-#ifndef __WXDEBUG__
- //prevent wxWidgets logging
- wxLogNull noWxLogs;
-#endif
};
-void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString& target, StatusUpdater* updateClass)
+void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString& target, StatusHandler* updateClass)
{
static UpdateWhileCopying copyAndUpdate; //single instantiation: after each execution thread enters wait phase
@@ -935,12 +992,6 @@ void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString&
}
-FreeFileSync::FreeFileSync(bool useRecycleBin) :
- recycleBinShouldBeUsed(useRecycleBin) {}
-
-FreeFileSync::~FreeFileSync() {}
-
-
bool FreeFileSync::recycleBinExists()
{
return recycler.recycleBinExists();
@@ -948,7 +999,7 @@ bool FreeFileSync::recycleBinExists()
inline
-SyncDirection getSyncDirection(const CompareFilesResult cmpResult, const SyncConfiguration& config)
+SyncConfiguration::Direction getSyncDirection(const CompareFilesResult cmpResult, const SyncConfiguration& config)
{
switch (cmpResult)
{
@@ -975,7 +1026,7 @@ SyncDirection getSyncDirection(const CompareFilesResult cmpResult, const SyncCon
default:
assert (false);
}
- return SYNC_DIR_NONE;
+ return SyncConfiguration::SYNC_DIR_NONE;
}
@@ -1003,15 +1054,15 @@ bool getBytesToTransfer(int& objectsToCreate,
//get data to process
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //delete file on left
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete file on left
dataToProcess = 0;
objectsToDelete = 1;
break;
- case SYNC_DIR_RIGHT: //copy from left to right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
dataToProcess = fileCmpLine.fileDescrLeft.fileSize.ToDouble();
objectsToCreate = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1019,15 +1070,15 @@ bool getBytesToTransfer(int& objectsToCreate,
case FILE_RIGHT_SIDE_ONLY:
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
dataToProcess = fileCmpLine.fileDescrRight.fileSize.ToDouble();;
objectsToCreate = 1;
break;
- case SYNC_DIR_RIGHT: //delete file on right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete file on right
dataToProcess = 0;
objectsToDelete = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1038,15 +1089,15 @@ bool getBytesToTransfer(int& objectsToCreate,
//get data to process
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
dataToProcess = fileCmpLine.fileDescrRight.fileSize.ToDouble();
objectsToOverwrite = 1;
break;
- case SYNC_DIR_RIGHT: //copy from left to right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
dataToProcess = fileCmpLine.fileDescrLeft.fileSize.ToDouble();
objectsToOverwrite = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1092,32 +1143,32 @@ void FreeFileSync::calcTotalBytesToSync(int& objectsToCreate,
}
-bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater)
+bool FreeFileSync::synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater)
{ //false if nothing was to be done
assert (statusUpdater);
- if (!filename.selectedForSynchronization) return false;
+ if (!cmpLine.selectedForSynchronization) return false;
wxString target;
//synchronize file:
- switch (filename.cmpResult)
+ switch (cmpLine.cmpResult)
{
case FILE_LEFT_SIDE_ONLY:
switch (config.exLeftSideOnly)
{
- case SYNC_DIR_LEFT: //delete files on left
- statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
- removeFile(filename.fileDescrLeft.filename);
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete files on left
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
+ removeFile(cmpLine.fileDescrLeft.fullName, useRecycleBin);
break;
- case SYNC_DIR_RIGHT: //copy files to right
- target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\"") +
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy files to right
+ target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName;
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") +
_(" to ") + wxT("\"") + target + wxT("\""));
- copyfileMultithreaded(filename.fileDescrLeft.filename, target, statusUpdater);
+ copyfileMultithreaded(cmpLine.fileDescrLeft.fullName, target, statusUpdater);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1127,18 +1178,18 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
case FILE_RIGHT_SIDE_ONLY:
switch (config.exRightSideOnly)
{
- case SYNC_DIR_LEFT: //copy files to left
- target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\"") +
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy files to left
+ target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName;
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") +
_(" to ") + wxT("\"") + target + wxT("\""));
- copyfileMultithreaded(filename.fileDescrRight.filename, target, statusUpdater);
+ copyfileMultithreaded(cmpLine.fileDescrRight.fullName, target, statusUpdater);
break;
- case SYNC_DIR_RIGHT: //delete files on right
- statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
- removeFile(filename.fileDescrRight.filename);
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete files on right
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
+ removeFile(cmpLine.fileDescrRight.fullName, useRecycleBin);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1148,23 +1199,23 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
case FILE_LEFT_NEWER:
case FILE_RIGHT_NEWER:
case FILE_DIFFERENT:
- switch (getSyncDirection(filename.cmpResult, config))
+ switch (getSyncDirection(cmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\"") +
- _(" overwriting ") + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") +
+ _(" overwriting ") + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
- removeFile(filename.fileDescrLeft.filename); //only used if switch activated by user, else file is simply deleted
- copyfileMultithreaded(filename.fileDescrRight.filename, filename.fileDescrLeft.filename, statusUpdater);
+ 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 SYNC_DIR_RIGHT: //copy from left to right
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\"") +
- _(" overwriting ") + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") +
+ _(" overwriting ") + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
- removeFile(filename.fileDescrRight.filename); //only used if switch activated by user, else file is simply deleted
- copyfileMultithreaded(filename.fileDescrLeft.filename, filename.fileDescrRight.filename, statusUpdater);
+ 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);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1181,34 +1232,34 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
}
-bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater)
+bool FreeFileSync::synchronizeFolder(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater)
{ //false if nothing was to be done
assert (statusUpdater);
- if (!filename.selectedForSynchronization) return false;
+ if (!cmpLine.selectedForSynchronization) return false;
wxString target;
//synchronize folders:
- switch (filename.cmpResult)
+ switch (cmpLine.cmpResult)
{
case FILE_LEFT_SIDE_ONLY:
switch (config.exLeftSideOnly)
{
- case SYNC_DIR_LEFT: //delete folders on left
- statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
- removeDirectory(filename.fileDescrLeft.filename);
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete folders on left
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
+ removeDirectory(cmpLine.fileDescrLeft.fullName, useRecycleBin);
break;
- case SYNC_DIR_RIGHT: //create folders on right
- target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
+ case SyncConfiguration::SYNC_DIR_RIGHT: //create folders on right
+ target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName;
statusUpdater->updateStatusText(wxString(_("Creating folder ")) + wxT("\"") + target + wxT("\""));
//some check to catch the error that directory on source has been deleted externally after the "compare"...
- if (!wxDirExists(filename.fileDescrLeft.filename))
- throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
+ if (!wxDirExists(cmpLine.fileDescrLeft.fullName))
+ throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
createDirectory(target);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1218,20 +1269,20 @@ bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const Sync
case FILE_RIGHT_SIDE_ONLY:
switch (config.exRightSideOnly)
{
- case SYNC_DIR_LEFT: //create folders on left
- target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
+ case SyncConfiguration::SYNC_DIR_LEFT: //create folders on left
+ target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName;
statusUpdater->updateStatusText(wxString(_("Creating folder ")) + wxT("\"") + target + wxT("\""));
//some check to catch the error that directory on source has been deleted externally after the "compare"...
- if (!wxDirExists(filename.fileDescrRight.filename))
- throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
+ if (!wxDirExists(cmpLine.fileDescrRight.fullName))
+ throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
createDirectory(target);
break;
- case SYNC_DIR_RIGHT: //delete folders on right
- statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
- removeDirectory(filename.fileDescrRight.filename);
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete folders on right
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
+ removeDirectory(cmpLine.fileDescrRight.fullName, useRecycleBin);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1333,10 +1384,10 @@ wxString FreeFileSync::formatFilesizeToShortString(const double filesize)
}
-vector<wxString> FreeFileSync::compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter)
+void compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter, vector<wxString>& output)
{
+ output.clear();
wxString input(compoundInput);
- vector<wxString> output;
//make sure input ends with delimiter - no problem with empty strings here
if (!input.EndsWith(delimiter))
@@ -1358,8 +1409,6 @@ vector<wxString> FreeFileSync::compoundStringToTable(const wxString& compoundInp
}
indexStart = indexEnd + 1;
}
-
- return output;
}
@@ -1401,30 +1450,34 @@ void mergeVectors(vector<wxString>& changing, const vector<wxString>& input)
}
-void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter)
+vector<wxString> FreeFileSync::compoundStringToFilter(const wxString& filterString)
{
- //load filters into vectors
//delimiters may be ';' or '\n'
- vector<wxString> includeList;
- vector<wxString> includePreProcessing = compoundStringToTable(includeFilter, wxT(";"));
- for (vector<wxString>::const_iterator i = includePreProcessing.begin(); i != includePreProcessing.end(); ++i)
- {
- vector<wxString> newEntries = compoundStringToTable(*i, wxT("\n"));
- mergeVectors(includeList, newEntries);
- }
+ vector<wxString> filterList;
+ vector<wxString> filterPreProcessing;
+ compoundStringToTable(filterString, wxT(";"), filterPreProcessing);
- vector<wxString> excludeList;
- vector<wxString> excludePreProcessing = compoundStringToTable(excludeFilter, wxT(";"));
- for (vector<wxString>::const_iterator i = excludePreProcessing.begin(); i != excludePreProcessing.end(); ++i)
+ for (vector<wxString>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i)
{
- vector<wxString> newEntries = compoundStringToTable(*i, wxT("\n"));
- mergeVectors(excludeList, newEntries);
+ vector<wxString> newEntries;
+ compoundStringToTable(*i, wxT("\n"), newEntries);
+ mergeVectors(filterList, newEntries);
}
+ return filterList;
+}
+
+
+void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter)
+{
+ //load filter into vectors of strings
+ //delimiters may be ';' or '\n'
+ vector<wxString> includeList = FreeFileSync::compoundStringToFilter(includeFilter);
+ vector<wxString> excludeList = FreeFileSync::compoundStringToFilter(excludeFilter);
+
//format entries
for (vector<wxString>::iterator i = includeList.begin(); i != includeList.end(); ++i)
formatFilterString(*i);
-
for (vector<wxString>::iterator i = excludeList.begin(); i != excludeList.end(); ++i)
formatFilterString(*i);
@@ -1433,14 +1486,14 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
//filter currentGridData
for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i)
{
- wxString filenameLeft = i->fileDescrLeft.filename;
- wxString filenameRight = i->fileDescrRight.filename;
+ wxString filenameLeft = i->fileDescrLeft.fullName;
+ wxString filenameRight = i->fileDescrRight.fullName;
formatFilenameString(filenameLeft);
formatFilenameString(filenameRight);
//process include filters
- if (i->fileDescrLeft.objType != TYPE_NOTHING)
+ if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING)
{
bool includedLeft = false;
for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j)
@@ -1457,7 +1510,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
}
}
- if (i->fileDescrRight.objType != TYPE_NOTHING)
+ if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING)
{
bool includedRight = false;
for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j)
@@ -1524,22 +1577,22 @@ wxString FreeFileSync::getFormattedDirectoryName(const wxString& dirname)
inline
bool deletionImminent(const FileCompareLine& line, const SyncConfiguration& config)
{ //test if current sync-line will result in deletion of files -> used to avoid disc space bottlenecks
- if ((line.cmpResult == FILE_LEFT_SIDE_ONLY && config.exLeftSideOnly == SYNC_DIR_LEFT) ||
- (line.cmpResult == FILE_RIGHT_SIDE_ONLY && config.exRightSideOnly == SYNC_DIR_RIGHT))
+ if ( (line.cmpResult == FILE_LEFT_SIDE_ONLY && config.exLeftSideOnly == SyncConfiguration::SYNC_DIR_LEFT) ||
+ (line.cmpResult == FILE_RIGHT_SIDE_ONLY && config.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT))
return true;
else
return false;
}
-class AlwaysWriteResult //this class ensures, that the result of the method below is ALWAYS written on exit, even if exceptions are thrown!
+class AlwaysWriteToGrid //this class ensures, that the result of the method below is ALWAYS written on exit, even if exceptions are thrown!
{
public:
- AlwaysWriteResult(FileCompareResult& grid) :
+ AlwaysWriteToGrid(FileCompareResult& grid) :
gridToWrite(grid)
{}
- ~AlwaysWriteResult()
+ ~AlwaysWriteToGrid()
{
removeRowsFromVector(gridToWrite, rowsProcessed);
}
@@ -1556,11 +1609,15 @@ private:
//synchronizes while processing rows in grid and returns all rows that have not been synced
-void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusUpdater* statusUpdater, bool useRecycleBin)
+void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusHandler* statusUpdater, const bool useRecycleBin)
{
assert (statusUpdater);
- AlwaysWriteResult writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
+#ifndef __WXDEBUG__
+ wxLogNull noWxLogs; //prevent wxWidgets logging
+#endif
+
+ AlwaysWriteToGrid writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
//inform about the total amount of data that will be processed from now on
int objectsToCreate = 0;
@@ -1574,12 +1631,10 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
grid,
config);
- statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, dataToProcess, FreeFileSync::synchronizeFilesProcess);
+ statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, dataToProcess, StatusHandler::PROCESS_SYNCHRONIZING);
try
{
- FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
-
// it should never happen, that a directory on left side has same name as file on right side. startCompareProcess() should take care of this
// and split into two "exists on one side only" cases
// Note: this case is not handled by this tool as this is considered to be a bug and must be solved by the user
@@ -1587,15 +1642,17 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
//synchronize folders:
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
{
- if (i->fileDescrLeft.objType == TYPE_DIRECTORY || i->fileDescrRight.objType == TYPE_DIRECTORY)
+ if ( i->fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY ||
+ i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
{
+
while (true)
{ //trigger display refresh
statusUpdater->requestUiRefresh();
try
{
- if (fileSyncObject.synchronizeFolder(*i, config, statusUpdater))
+ if (FreeFileSync::synchronizeFolder(*i, config, useRecycleBin, statusUpdater))
//progress indicator update
//indicator is updated only if directory is synched correctly (and if some sync was done)!
statusUpdater->updateProcessedData(1, 0); //each call represents one processed file/directory
@@ -1606,11 +1663,11 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -1627,7 +1684,8 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
{
- if (i->fileDescrLeft.objType == TYPE_FILE || i->fileDescrRight.objType == TYPE_FILE)
+ if ( i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE ||
+ i->fileDescrRight.objType == FileDescrLine::TYPE_FILE)
{
if (deleteLoop && deletionImminent(*i, config) ||
!deleteLoop && !deletionImminent(*i, config))
@@ -1638,7 +1696,7 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
try
{
- if (fileSyncObject.synchronizeFile(*i, config, statusUpdater))
+ if (FreeFileSync::synchronizeFile(*i, config, useRecycleBin, statusUpdater))
{
//progress indicator update
//indicator is updated only if file is sync'ed correctly (and if some sync was done)!
@@ -1662,11 +1720,11 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -1690,27 +1748,26 @@ void FreeFileSync::addSubElements(set<int>& subElements, const FileCompareResult
{
wxString relevantDirectory;
- if (relevantRow.fileDescrLeft.objType == TYPE_DIRECTORY)
- relevantDirectory = relevantRow.fileDescrLeft.relFilename;
+ if (relevantRow.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
+ relevantDirectory = relevantRow.fileDescrLeft.relativeName + GlobalResources::fileNameSeparator; //fileNameSeparator needed to exclude subfile/dirs only
- else if (relevantRow.fileDescrRight.objType == TYPE_DIRECTORY)
- relevantDirectory = relevantRow.fileDescrRight.relFilename;
+ else if (relevantRow.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
+ relevantDirectory = relevantRow.fileDescrRight.relativeName + GlobalResources::fileNameSeparator;
else
return;
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
- if ( i->fileDescrLeft.relFilename.StartsWith(relevantDirectory) ||
- i->fileDescrRight.relFilename.StartsWith(relevantDirectory))
+ if ( i->fileDescrLeft.relativeName.StartsWith(relevantDirectory) ||
+ i->fileDescrRight.relativeName.StartsWith(relevantDirectory))
subElements.insert(i - grid.begin());
}
-void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, StatusUpdater* statusUpdater, bool useRecycleBin)
+void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, ErrorHandler* errorHandler, const bool useRecycleBin)
{
- FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
-
- set<int> rowsToDeleteInGrid;
+ //remove deleted rows from grid
+ AlwaysWriteToGrid writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
//remove from hd
for (set<int>::iterator i = rowsToDelete.begin(); i != rowsToDelete.end(); ++i)
@@ -1721,45 +1778,44 @@ void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& ro
{
try
{
- if (currentCmpLine.fileDescrLeft.objType == TYPE_FILE)
- fileSyncObject.removeFile(currentCmpLine.fileDescrLeft.filename);
- else if (currentCmpLine.fileDescrLeft.objType == TYPE_DIRECTORY)
- fileSyncObject.removeDirectory(currentCmpLine.fileDescrLeft.filename);
+ if (currentCmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE)
+ FreeFileSync::removeFile(currentCmpLine.fileDescrLeft.fullName, useRecycleBin);
+ else if (currentCmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
+ FreeFileSync::removeDirectory(currentCmpLine.fileDescrLeft.fullName, useRecycleBin);
+
+ if (currentCmpLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE)
+ FreeFileSync::removeFile(currentCmpLine.fileDescrRight.fullName, useRecycleBin);
+ else if (currentCmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
+ FreeFileSync::removeDirectory(currentCmpLine.fileDescrRight.fullName, useRecycleBin);
+
+ //remove deleted row from grid
+ writeOutput.rowProcessedSuccessfully(*i);
- if (currentCmpLine.fileDescrRight.objType == TYPE_FILE)
- fileSyncObject.removeFile(currentCmpLine.fileDescrRight.filename);
- else if (currentCmpLine.fileDescrRight.objType == TYPE_DIRECTORY)
- fileSyncObject.removeDirectory(currentCmpLine.fileDescrRight.filename);
+ //retrieve all files and subfolder gridlines that are dependent from this deleted entry
+ set<int> additionalRowsToDelete;
+ addSubElements(additionalRowsToDelete, grid, grid[*i]);
+
+ //...and remove them also
+ for (set<int>::iterator j = additionalRowsToDelete.begin(); j != additionalRowsToDelete.end(); ++j)
+ writeOutput.rowProcessedSuccessfully(*j);
- rowsToDeleteInGrid.insert(*i);
break;
}
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = errorHandler->reportError(error.show());
- if (rv == StatusUpdater::continueNext)
+ if (rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue in loop
else
assert (false);
}
}
}
-
- //retrieve all files and subfolder gridlines that are dependent from deleted directories and add them to the list
- set<int> additionalRowsToDelete;
- for (set<int>::iterator i = rowsToDeleteInGrid.begin(); i != rowsToDeleteInGrid.end(); ++i)
- addSubElements(additionalRowsToDelete, grid, grid[*i]);
-
- for (set<int>::iterator i = additionalRowsToDelete.begin(); i != additionalRowsToDelete.end(); ++i)
- rowsToDeleteInGrid.insert(*i);
-
- //remove deleted rows from grid
- removeRowsFromVector(grid, rowsToDeleteInGrid);
}
@@ -1780,12 +1836,12 @@ bool FreeFileSync::foldersAreValidForComparison(const vector<FolderPair>& folder
//check if folder exists
if (!wxDirExists(leftFolderName))
{
- errorMessage = wxString(_("Directory does not exist. Please select a new one: ")) + wxT("\"") + leftFolderName + wxT("\"");
+ errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + leftFolderName + wxT("\"");
return false;
}
if (!wxDirExists(rightFolderName))
{
- errorMessage = wxString(_("Directory does not exist. Please select a new one: ")) + wxT("\"") + rightFolderName + wxT("\"");
+ errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + rightFolderName + wxT("\"");
return false;
}
}
@@ -1793,3 +1849,75 @@ bool FreeFileSync::foldersAreValidForComparison(const vector<FolderPair>& folder
}
+void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler)
+{
+ if (timeInSeconds == 0)
+ return;
+
+ wxArrayString fileList;
+ wxArrayString dirList;
+
+ while (true) //own scope for directory access to not disturb file access!
+ {
+ fileList.Clear();
+ dirList.Clear();
+
+ //get all files and folders from directory (and subdirectories)
+ GetAllFilesSimple traverser(fileList, dirList);
+
+ wxDir dir(parentDirectory);
+ if (dir.Traverse(traverser) != (size_t)-1)
+ break; //traversed successfully
+ else
+ {
+ ErrorHandler::Response rv = errorHandler->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + parentDirectory + wxT("\""));
+ if (rv == ErrorHandler::CONTINUE_NEXT)
+ break;
+ else if (rv == ErrorHandler::RETRY)
+ ; //continue with loop
+ else
+ assert (false);
+ }
+ }
+
+
+ //this part is only a bit slower than direct Windows API-access!
+ wxDateTime modTime;
+ for (unsigned int j = 0; j < fileList.GetCount(); ++j)
+ {
+ while (true) //own scope for directory access to not disturb file access!
+ {
+ try
+ {
+ wxFileName file(fileList[j]);
+ if (!file.GetTimes(NULL, &modTime, NULL)) //get modification time
+ throw FileError(wxString(_("Error changing modification time: ")) + wxT("\"") + fileList[j] + 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("\""));
+
+ break;
+ }
+ catch (const FileError& error)
+ {
+ ErrorHandler::Response rv = errorHandler->reportError(error.show());
+ if (rv == ErrorHandler::CONTINUE_NEXT)
+ break;
+ else if (rv == ErrorHandler::RETRY)
+ ; //continue with loop
+ else
+ assert (false);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/FreeFileSync.h b/FreeFileSync.h
index c1b4fd9d..22a0f4e1 100644
--- a/FreeFileSync.h
+++ b/FreeFileSync.h
@@ -10,12 +10,6 @@
using namespace std;
-enum SyncDirection
-{
- SYNC_DIR_LEFT,
- SYNC_DIR_RIGHT,
- SYNC_DIR_NONE
-};
enum CompareVariant
{
@@ -25,15 +19,33 @@ enum CompareVariant
struct SyncConfiguration
{
- SyncDirection exLeftSideOnly;
- SyncDirection exRightSideOnly;
- SyncDirection leftNewer;
- SyncDirection rightNewer;
- SyncDirection different;
+ SyncConfiguration() :
+ exLeftSideOnly(SYNC_DIR_RIGHT),
+ exRightSideOnly(SYNC_DIR_RIGHT),
+ leftNewer(SYNC_DIR_RIGHT),
+ rightNewer(SYNC_DIR_RIGHT),
+ different(SYNC_DIR_RIGHT) {}
+
+ enum Direction
+ {
+ SYNC_DIR_LEFT,
+ SYNC_DIR_RIGHT,
+ SYNC_DIR_NONE
+ };
+
+ Direction exLeftSideOnly;
+ Direction exRightSideOnly;
+ Direction leftNewer;
+ Direction rightNewer;
+ Direction different;
};
+
struct MainConfiguration
-{ //Compare setting
+{
+ MainConfiguration();
+
+ //Compare setting
CompareVariant compareVar;
//Synchronisation settings
@@ -44,32 +56,28 @@ struct MainConfiguration
wxString includeFilter;
wxString excludeFilter;
+
//misc options
bool useRecycleBin; //use Recycle bin when deleting or overwriting files while synchronizing
bool continueOnError; //hides error messages during synchronization
};
-struct FileInfo
-{
- wxULongLong fileSize; //unit: bytes!
- wxString lastWriteTime;
- wxULongLong lastWriteTimeRaw; //unit: seconds!
-};
-
-enum ObjectType
-{
- TYPE_NOTHING,
- TYPE_DIRECTORY,
- TYPE_FILE
-};
struct FileDescrLine
{
FileDescrLine() : objType(TYPE_NOTHING) {}
- wxString filename; // == directory + relFilename
+ enum ObjectType
+ {
+ TYPE_NOTHING,
+ TYPE_DIRECTORY,
+ TYPE_FILE
+ };
+
+ wxString fullName; // == directory + relativeName
wxString directory; //directory to be synced
- wxString relFilename; //filename without directory that is being synchronized
+ wxString relativeName; //fullName without directory that is being synchronized
+ //Note on performance: Keep redundant information "directory" and "relativeName"! Extracting info from "fullName" results in noticeable performance loss!
wxString lastWriteTime;
wxULongLong lastWriteTimeRaw;
wxULongLong fileSize;
@@ -81,30 +89,30 @@ struct FileDescrLine
//Windows does NOT distinguish between upper/lower-case
bool operator>(const FileDescrLine& b ) const
{
- return (relFilename.CmpNoCase(b.relFilename) > 0);
+ return (relativeName.CmpNoCase(b.relativeName) > 0);
}
bool operator<(const FileDescrLine& b) const
{
- return (relFilename.CmpNoCase(b.relFilename) < 0);
+ return (relativeName.CmpNoCase(b.relativeName) < 0);
}
bool operator==(const FileDescrLine& b) const
{
- return (relFilename.CmpNoCase(b.relFilename) == 0);
+ return (relativeName.CmpNoCase(b.relativeName) == 0);
}
#elif defined FFS_LINUX
//Linux DOES distinguish between upper/lower-case
bool operator>(const FileDescrLine& b ) const
{
- return (relFilename.Cmp(b.relFilename) > 0);
+ return (relativeName.Cmp(b.relativeName) > 0);
}
bool operator<(const FileDescrLine& b) const
{
- return (relFilename.Cmp(b.relFilename) < 0);
+ return (relativeName.Cmp(b.relativeName) < 0);
}
bool operator==(const FileDescrLine& b) const
{
- return (relFilename.Cmp(b.relFilename) == 0);
+ return (relativeName.Cmp(b.relativeName) == 0);
}
#else
adapt this
@@ -122,7 +130,7 @@ enum CompareFilesResult
FILE_DIFFERENT,
FILE_EQUAL,
- FILE_INVALID //error situation
+ FILE_UNDEFINED
};
@@ -142,130 +150,72 @@ typedef vector<FileCompareLine> FileCompareResult;
typedef int GridViewLine;
typedef vector<GridViewLine> GridView; //vector of references to lines in FileCompareResult
+
struct FolderPair
{
wxString leftDirectory;
wxString rightDirectory;
};
-class GetAllFilesFull : public wxDirTraverser
-{
-public:
- GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusUpdater* 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;
- StatusUpdater* statusUpdater;
-};
-
-//Note: the following lines are a performance optimization for deleting elements from a vector. It is incredibly faster to create a new
-//vector and leave specific elements out than to delete row by row and force recopying of most elements for each single deletion (linear vs quadratic runtime)
-template <class T>
-void removeRowsFromVector(vector<T>& grid, const set<int>& rowsToRemove)
-{
- vector<T> temp;
- int rowToSkip = -1; //keep it an INT!
-
- set<int>::iterator rowToSkipIndex = rowsToRemove.begin();
-
- if (rowToSkipIndex != rowsToRemove.end())
- rowToSkip = *rowToSkipIndex;
-
- for (int i = 0; i < int(grid.size()); ++i)
- {
- if (i != rowToSkip)
- temp.push_back(grid[i]);
- else
- {
- ++rowToSkipIndex;
- if (rowToSkipIndex != rowsToRemove.end())
- rowToSkip = *rowToSkipIndex;
- }
- }
- grid.swap(temp);
-}
class RecycleBin;
-class DirectoryDescrBuffer;
-
-class FreeFileSync
+namespace FreeFileSync
{
- friend class DirectoryDescrBuffer;
-
-public:
- FreeFileSync(bool useRecycleBin);
- ~FreeFileSync();
-
- //identifiers of different processes
- static const int scanningFilesProcess = 1;
- static const int compareFileContentProcess = 2;
- static const int synchronizeFilesProcess = 3;
-
- //main function for compare
- static void startCompareProcess(FileCompareResult& output, const vector<FolderPair>& directoryPairsFormatted, const CompareVariant cmpVar, StatusUpdater* statusUpdater);
+ //main functions for compare
+ bool foldersAreValidForComparison(const vector<FolderPair>& folderPairs, wxString& errorMessage);
+ void startCompareProcess(const vector<FolderPair>& directoryPairsFormatted, const CompareVariant cmpVar, FileCompareResult& output, StatusHandler* statusUpdater);
//main function for synchronization
- static void startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusUpdater* statusUpdater, bool useRecycleBin);
+ void startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusHandler* statusUpdater, const bool useRecycleBin);
- static bool foldersAreValidForComparison(const vector<FolderPair>& folderPairs, wxString& errorMessage);
- static bool recycleBinExists(); //test existence of Recycle Bin API on current system
+ bool recycleBinExists(); //test existence of Recycle Bin API on current system
- static vector<wxString> compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter); //convert ';'-separated list into table of strings
+ void deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, ErrorHandler* errorHandler, const bool useRecycleBin);
+ void addSubElements(set<int>& subElements, const FileCompareResult& grid, const FileCompareLine& relevantRow);
- static void deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, StatusUpdater* statusUpdater, bool useRecycleBin);
- static 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);
- static void filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter);
- static void removeFilterOnCurrentGridData(FileCompareResult& currentGridData);
+ wxString formatFilesizeToShortString(const wxULongLong& filesize);
+ wxString formatFilesizeToShortString(const double filesize);
+ wxString getFormattedDirectoryName(const wxString& dirname);
- static wxString formatFilesizeToShortString(const wxULongLong& filesize);
- static wxString formatFilesizeToShortString(const double filesize);
- static wxString getFormattedDirectoryName(const wxString& dirname);
+ void calcTotalBytesToSync(int& objectsToCreate,
+ int& objectsToOverwrite,
+ int& objectsToDelete,
+ double& dataToProcess,
+ const FileCompareResult& fileCmpResult,
+ const SyncConfiguration& config);
- static void calcTotalBytesToSync(int& objectsToCreate,
- int& objectsToOverwrite,
- int& objectsToDelete,
- double& dataToProcess,
- const FileCompareResult& fileCmpResult,
- const SyncConfiguration& config);
+ void swapGrids(FileCompareResult& grid);
- static void swapGrids(FileCompareResult& grid);
+ void adjustModificationTimes(const wxString& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler);
- static const wxString FfsLastConfigFile;
+ const wxString FfsLastConfigFile = wxT("LastRun.ffs_gui");
+ const wxString FfsGlobalSettingsFile = wxT("GlobalSettings.xml");
- static void getFileInformation(FileInfo& output, const wxString& filename);
-private:
- bool synchronizeFile(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater); // false if nothing had to be done
- bool synchronizeFolder(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater); // false if nothing had to be done
+//+++++++++++++++++++SUBROUTINES++++++++++++++++++++++++++
+ //create comparison result table and fill relation except for files existing on both sides
+ void performBaseComparison(const vector<FolderPair>& directoryPairsFormatted,
+ FileCompareResult& output,
+ StatusHandler* statusUpdater);
+
+ bool synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater); // false if nothing had to be done
+ bool synchronizeFolder(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater); // false if nothing had to be done
- //file copy functionality -> keep instance-bound to to be able to prevent wxWidgets-logging
- void removeDirectory(const wxString& directory);
- void removeFile(const wxString& filename);
- void copyfileMultithreaded(const wxString& source, const wxString& target, StatusUpdater* updateClass);
+ //file functionality
+ void removeDirectory(const wxString& directory, const bool useRecycleBin);
+ void removeFile(const wxString& filename, const bool useRecycleBin);
+ void copyfileMultithreaded(const wxString& source, const wxString& target, StatusHandler* updateClass);
void createDirectory(const wxString& directory, int level = 0); //level is used internally only
- //some special file functions
- static void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusUpdater* updateClass = 0);
+ //misc
+ vector<wxString> compoundStringToFilter(const wxString& filterString); //convert compound string, separated by ';' or '\n' into formatted vector of wxStrings
- bool recycleBinShouldBeUsed;
- static RecycleBin recycler;
-#ifndef __WXDEBUG__
- //prevent wxWidgets logging
- wxLogNull noWxLogs;
-#endif
-};
+ extern RecycleBin recycler;
+}
class FileError //Exception class used to notify file/directory copy/delete errors
diff --git a/Makefile_Win_ANSI.cmd b/Makefile_Win_ANSI.cmd
deleted file mode 100644
index a586b60c..00000000
--- a/Makefile_Win_ANSI.cmd
+++ /dev/null
@@ -1,32 +0,0 @@
-::set these variables to the appropriate directories
-set widgets=C:\Programme\CodeBlocks\wxWidgets
-set widgetslib=C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\msw
-set sources=C:\Programme\CodeBlocks\Projects\FreeFileSync
-set mingw=C:\Programme\CodeBlocks\MinGW\bin
-
-path=%path%;%mingw%
-::convert file from UTF-8 to standard ANSI encoding; ICONV is part of MinGW - MSYS Supplementary Tools
-iconv -f UTF-8 -t ISO-8859-1 %sources%\ui\guiGenerated.cpp > %sources%\ui\guiGenerated_ansi.cpp
-
-set parameters=-Wall -pipe -mthreads -D__GNUWIN32__ -D__WXMSW__ -DFFS_WIN -O2 -DNDEBUG -DTIXML_USE_STL
-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
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\FreeFileSync.cpp -o obj\FreeFileSync.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%\ui\guiGenerated_ansi.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
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\ui\syncDialog.cpp -o obj\SyncDialog.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\customGrid.cpp -o obj\CustomGrid.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\resources.cpp -o obj\Resources.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\misc.cpp -o obj\misc.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\ui\smallDialogs.cpp -o obj\SmallDialogs.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\tinyxml\tinyxml.cpp -o obj\tinyxml.o
-mingw32-g++.exe %parameters% -I%widgets%\include -I%widgets%\contrib\include -I%widgetslib% -c %sources%\library\tinyxml\tinystr.cpp -o obj\tinystr.o
-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
-
-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\FreeFileSync.o obj\globalFunctions.o obj\multithreading.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 -s -mthreads -lwxmsw28_adv -lwxmsw28_core -lwxbase28 -lwxpng -lwxzlib -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -lwsock32 -lodbc32 -mwindows
-del %sources%\ui\guiGenerated_ansi.cpp
-pause \ No newline at end of file
diff --git a/Makefile_Win_Unicode.cmd b/Makefile_Win_Unicode.cmd
index 59fde788..61d53dce 100644
--- a/Makefile_Win_Unicode.cmd
+++ b/Makefile_Win_Unicode.cmd
@@ -1,8 +1,8 @@
::set these variables to the appropriate directories
-set widgets=C:\Programme\CodeBlocks\wxWidgets
-set widgetslib=C:\Programme\CodeBlocks\wxWidgets\lib\gcc_lib\mswu
+set widgets=C:\Programme\C++\wxWidgets
+set widgetslib=C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu
set sources=.
-set mingw=C:\Programme\CodeBlocks\MinGW\bin
+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
path=%path%;%mingw%
diff --git a/Readme.txt b/Readme.txt
index a21fa03a..f9493072 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -1,4 +1,4 @@
-FreeFileSync v1.11
+FreeFileSync v1.12
------------------
Usage
diff --git a/Resources.dat b/Resources.dat
index 5ef771a2..fd4e61a8 100644
--- a/Resources.dat
+++ b/Resources.dat
Binary files differ
diff --git a/dutch.lng b/dutch.lng
new file mode 100644
index 00000000..e2dadb49
--- /dev/null
+++ b/dutch.lng
@@ -0,0 +1,596 @@
+ 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
+ Time:
+ Tijd:
+ Byte
+ Byte
+ GB
+ GB
+ MB
+ MB
+ PB
+ 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
+&Abort
+&Afbreken
+&About...
+&Informatie...
+&Adjust file times
+&Pas bestandstijden aan
+&Advanced
+&Geavanceerd
+&Back
+&Terug
+&Cancel
+&Annuleren
+&Compare
+&Vergelijken
+&Continue
+&Doorgaan
+&Create
+&Creëer
+&Create batch job
+&Creëer batchjob
+&Default
+&Standaard
+&Export file list
+&Exporteer bestandslijst
+&File
+&Bestand
+&Help
+&Help
+&Language
+&Taal
+&OK
+&OK
+&Pause
+&Pause
+&Quit
+&Afsluiten
+&Retry
+&Opnieuw proberen
+&Start
+&Start
+&Synchronize
+&Synchroniseer
+(-) filtered out from sync-process\n
+(-) wordt niet gesynchroniseerd\n
+,
+.
+- different
+- verschillend
+- different (same date, different size)
+- verschillend (zelfde datum, verschillende grootte)
+- equal
+- gelijk
+- exists left only
+- bestaat alleen links
+- exists right only
+- bestaat alleen rechts
+- left
+- links
+- left newer
+- links is nieuwer
+- right
+- rechts
+- right newer
+- rechts is nieuwer
+- same date (different size)
+- zelfde datum (verschillende grootte)
+-------------------------------------------------
+-----------------------------------------------------
+---------\n
+-----------\n
+-Open-Source file synchronization-
+-Open-Source bestandssynchronisatie-
+.
+,
+1. &Compare
+1. &Vergelijk
+1. Enter full file or directory names separated by ';' or a new line.
+1. Geef de volledige naam van het bestand of pad gescheiden bij ';' of een nieuwe regel.
+2. &Synchronize...
+2. &Synchroniseer...
+2. Use wildcard characters '*' and '?'.
+2. U kunt gebruik maken van wildcard karakters zoals '*' en '?'.
+3. Exclude files directly on main grid via context menu.
+3. Sluit bestanden direct uit in het hoofscherm via een contextmenu
+4. Keep the number of entries small for best performance.
+4. Houd het aantal klein voor de beste prestaties
+<< left file is newer\n
+<< linker bestand is nieuwer\n
+<Directory>
+<Pad>
+<multiple selection>
+<veelvoudige selectie>
+<| file on left side only\n
+<| bestand bestaat alleen links\n
+== files are equal\n\n
+== bestanden zijn gelijk\n\n
+>> right file is newer\n
+>> rechter bestand is nieuwer\n
+Abort
+Afbreken
+Abort requested: Waiting for current operation to finish...
+Bezig met afbreken: wachten op beëindigen huidige handeling...
+Aborted
+Afgebroken
+About
+Informatie
+Action
+Actie
+Add folder pair
+Voeg 1 paar gekoppelde mappen toe
+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:
+Past de bewerkingstijden aan van alle bestanden in de gespecificeerde map en onderliggende mappen. Deze handeling is misschien nodig als u synchroniseerd naar een FAT32-schijf en de zomertijd is ingeschakeld. Voor meer informatie hierover kunt u terecht bij het volgende artikel:
+All file times have been adjusted successfully!
+Alle bestandstijden zijn succesvol aangepast!
+All items have been synchronized!
+Alle bestanden zijn gesynchroniseerd!
+An error occured
+Er is een fout opgetreden
+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:
+Zoals de naam suggereert, worden twee bestanden met dezelfde naam alleen gemarkeerd als gelijk, als ze precies dezelfde inhoud hebben. Deze optie is handig voor een consistentiecontrole in plaats van back-up handelingen. Daarom worden de tijdstempels niet bekeken.\n\n Met deze optie aan is de beslissingsboom korter:
+Assemble a batch file with the following settings. To start synchronization in batch mode simply execute this file or schedule it in your operating system's task planner.
+Creëer een batchbestand met de volgende instellingen. Om synchronisatie\nin batchmodus uit te voeren kunt u dit bestand uitvoeren of opnemen in de taakplanner van het systeem.
+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:
+Choose to hide filtered files/directories from list
+Gefilterde bestanden niet/wel weergeven
+Comma separated list
+Komma gescheiden lijst
+Compare both sides
+Beide zijden vergelijken
+Compare by \"File content\"
+Vergelijk met \"bestandsinhoud\"
+Compare by \"File size and date\"
+Vergelijk met \"bestandsgrootte en -datum\"
+Compare by...
+Vergelelijk met...
+Comparing content
+Vergelijken van inhoud
+Comparing content of files
+Vergelijken van bestandsinhoud
+Comparing...
+Vergelijken...
+Completed
+Volbracht
+Configuration
+Configuratie
+Configuration loaded!
+Configuratie geladen!
+Configuration overview:
+Configuratie overzicht:
+Configuration saved!
+Configuratie opgeslagen!
+Configure filter
+Configuratie filter
+Configure filter...
+Configuratie filter...
+Configure your own synchronization rules.
+Configureer uw eigen synchronisatieregels.
+Confirm
+Bevestig
+Continue
+Doorgaan
+Continue on error
+Doorgaan bij fout
+Continue on next errors
+Doorgaan bij volgende fouten
+Copy from left to right
+Kopieer van links naar rechts
+Copy from left to right overwriting
+Kopieer en overschrijf van links naar rechts
+Copy from right to left
+Kopieer van rechts naar links
+Copy from right to left overwriting
+Kopieer en overschrijf van rechts naar links
+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
+Create a batch job
+Creëer batchjob
+Create:
+Aanmaken:
+Creating folder
+Folder aanmaken
+Current operation:
+Huidige operatie:
+Custom
+Gebruik
+DECISION TREE
+BESLISSINGSBOOM
+Data remaining:
+Resterende data:
+Data:
+Data:
+Date
+Datum
+Delete files/folders existing on left side only
+Verwijder bestanden/folders die alleen links bestaan
+Delete files/folders existing on right side only
+Verwijder bestanden/folders die alleen rechts bestaan
+Delete files\tDEL
+Verwijder bestanden\tDEL
+Delete:
+Verwijderen:
+Deleting file
+Bestand wordt verwijderd
+Deleting folder
+Folder wordt verwijderd
+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
+Do nothing
+Geen actie ondernemen
+Do you really want to delete the following objects(s)?
+Weet u zeker dat u de volgende bestanden wilt verwijderen?
+Do you really want to move the following objects(s) to the recycle bin?
+Weet u zeker dat u de volgende bestanden naar de prullenbak wilt verplaatsen?
+Donate with PayPal
+Doneer met PayPal
+Drag && drop
+Drag en drop
+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 map
+Error deleting directory
+Er is een fout opgetreden bij het verwijderen van een map
+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:
+Example
+Voorbeeld
+Exclude
+Uitsluiten
+Exclude temporarily
+Tijdelijk uitsluiten
+Feedback and suggestions are welcome at:
+Tips en suggesties zijn welkom op:
+File content
+Bestandsinhoud
+File list exported!
+Bestandslijst geëxporteerd!
+File size and date
+Bestandsgrootte en -datum
+Filename
+Bestandsnaam
+Files are found equal if\n - file content\nis the same.
+Bestanden worden gelijk beschouwd als,\n - de inhoud\novereenkomt.
+Files are found equal if\n - filesize\n - last write time and date\nare the same.
+Bestanden worden gelijk beschouwd als,\n - de grootte\n - datum en tijdstip van de laatste wijziging\novereenkomt.
+Files remaining:
+Resterende bestanden:
+Files that exist on both sides and have different content
+Bestanden die aan beide kanten bestaan maar een verschillende inhoud hebben
+Files that exist on both sides, have same date but different filesizes
+Bestanden die aan beide kanten bestaan, dezelfde datum hebben maar verschillende bestandgroottes
+Files that exist on both sides, left one is newer
+Bestanden die aan beide kanten bestaan, maar waarvan de linkerkant nieuwer is
+Files that exist on both sides, right one is newer
+Bestanden die aan beide kanten bestaan, maar waarvan de rechterkant nieuwer is
+Files/folders remaining:
+Resterende bestanden/mappen:
+Files/folders scanned:
+Aantal bestanden/mappen gescand:
+Files/folders that exist on left side only
+Bestanden/mappen die alleen aan de linkerkant bestaan
+Files/folders that exist on right side only
+Bestanden/mappen die alleen aan de rechterkant bestaan
+Filter
+Filter
+Filter active: Press again to deactivate
+Filter actief: nogmaals klikken om uit te zetten
+Filter files
+Filter bestanden
+Filter view
+Bekijk het filter
+Folder pair
+Gekoppelde mappen
+FreeFileSync (Date:
+FreeFileSync (Datum:
+FreeFileSync - Folder Comparison and Synchronization
+FreeFileSync - Mappen vergelijken en synchroniseren
+FreeFileSync Batch Job
+FreeFileSync batchjob
+FreeFileSync at Sourceforge
+FreeFileSync op Sourceforge
+FreeFileSync batch file
+FreeFileSync batchbestand
+FreeFileSync configuration
+FreeFileSync configuratie
+Help
+Help
+Hide files that are different
+Verberg bestanden die verschillend zijn
+Hide files that are equal
+Verberg bestanden die gelijk zijn
+Hide files that are newer on left
+Verberg bestanden die aan de linkerkant nieuwer zijn
+Hide files that are newer on right
+Verberg bestanden die aan de rechterkant nieuwer zijn
+Hide files that exist on left side only
+Verberg bestanden die alleen aan de linkerkant bestaan
+Hide files that exist on right side only
+Verberg bestanden die alleen aan de rechterkant bestaan
+Hide filtered items
+Verberg gefilterde items
+Hide further error messages during the current process and continue
+Ga door en geef volgende foutmeldingen tijdens dit proces niet meer weer
+Hides error messages during synchronization:\nThey are collected and shown as a list at the end of the process
+Verbergt foutmeldingen tijdens het synchroniseren:\nze worden verzameld en op het eind in een lijst getoond
+Hints:
+Tips:
+Homepage:
+Homepage:
+If you like FFS:
+Als het programma u bevalt:
+Include
+Gebruiken
+Include temporarily
+Gebruik tijdelijk
+Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\*
+Gebruiken: *.doc;*.zip;*.exe\nUitsluiten: *\\temp\\*
+Info
+Info
+Information
+Informatie
+Initialization of Recycle Bin failed! It cannot be used!
+Initialiseren van de prullenbak is mislukt. Het kan niet worden gebruikt!
+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
+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...
+Laad met behulp van...
+Log-messages:\n-------------
+Logberichten:\n---------------
+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!
+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
+Aantal mappen en bestanden die zullen worden verwijderd
+Number of files that will be overwritten
+Aantal bestanden dat zal worden overschreven
+One way ->
+Naar rechts ->
+Only files/directories that pass filtering will be selected for synchronization.\nThe filter will be applied to the full name including path prefix.
+Alleen de niet gefilterde bestanden worden geselecteerd voor synchronisatie.\nHet filter wordt toegepast op de volledige naam inclusief pad-voorvoegsel.
+Open synchronization dialog
+Open de synchronisatie-instellingen
+Open with Explorer\tD-Click
+Open met Verkenner\tD-Click
+Operation aborted!
+Operatie afgebroken!
+Operation:
+Voortgang:
+Pause
+Pause
+Please fill all empty directory fields.
+Vul alstublieft aan beide kanten een pad in.
+Press button to activate filter
+Druk op de knop om het filter te activeren.
+Preview
+Voorbeeld
+Published under the GNU General Public License:
+Gepubliceerd onder de GNU General Public License:
+Quit
+Afsluiten
+Relative path
+Relatieve pad
+Remove folder pair
+Verwijder 1 paar gekoppelde mappen
+Result
+Resultaat
+Right folder:
+Rechter map:
+Save current configuration to file
+Sla de huidige instellingen op in een bestand
+Saved aborted!
+Opslaan afgebroken!
+Scanning
+Scannen
+Scanning...
+Data wordt doorlopen...
+Select a folder
+Selecteer een map
+Select folder
+Selecteer een folder
+Select variant:
+Selecteer een variant:
+Set filter for synchronization
+Filter instellen
+Show files that are different
+Geef bestanden die verschillend zijn weer
+Show files that are equal
+Geef bestanden die gelijk zijn weer
+Show files that are newer on left
+Geef bestanden weer die nieuwer zijn aan de linkerkant
+Show files that are newer on right
+Geef bestanden weer die nieuwer zijn aan de rechterkant
+Show files that exist on left side only
+Geef bestanden weer die alleen bestaan aan de linkerkant
+Show files that exist on right side only
+Geef bestanden weer die alleen bestaan aan de rechterkant
+Silent mode
+Stille modus
+Size
+Grootte
+Source code written completely in C++ utilizing:
+Broncode compleet geschreven in C++ met behulp van:
+Start
+Start
+Start synchronization
+Start synchroniseren
+Stop
+Stop
+Swap sides
+Verwissel van kant
+SyncJob.ffs_batch
+SyncJob.ffs_batch
+Synchronization aborted!
+Synchronisatie afgebroken!
+Synchronization completed successfully.
+Synchronisatie succesvol afgerond.
+Synchronization completed with errors!
+Synchronisatie afgerond. Er zijn fouten opgetreden.
+Synchronization settings
+Synchronisatie instellingen
+Synchronization status
+Synchronisatie: status
+Synchronize all .doc, .zip and .exe files except everything from folder \"temp\".
+Synchroniseer alle .doc, .zip en .exe bestanden behalve alles uit de map \"temp\".
+Synchronize both sides simultaneously: Copy new or updated files in both directions.
+Synchroniseer beide zijde tegelijkertijd: kopieer nieuwe of geüpdatete bestanden in beide richtingen.
+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 anymore!
+Het geselecteerde bestand bestaat niet meer!
+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:
+Verstreken tijd:
+Time shift in seconds
+Timeshift in seconden
+Total amount of data that will be transferred
+Hoeveelheid data die verplaatst word
+Total time:
+Totale tijd:
+Two way <->
+Beide zijden <->
+Unable to create logfile!
+Niet mogelijk om een logbestand aan te maken!
+Unable to initialize Recycle Bin!
+De prullenbak kon niet worden geïnitialiseerd!
+Unresolved errors occured during operation!
+Er is een onbekende fout opgetreden tijdens de handeling!
+Update:
+Overschrijven:
+Use Recycle Bin
+Gebruik de prullenbak
+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
+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:
+\n\nContinue with next object, retry or abort comparison?
+\n\nDoorgaan met volgende object, opnieuw proberen of het vergelijken afbreken?
+\n\nContinue with next object, retry or abort synchronization?
+\n\nDoorgaan met volgende object, opnieuw proberen of de synchronisatie afbreken?
+\n\nInformation: If you skip the error and continue or abort a re-compare will be necessary!
+\n\nInformatie: Als u de fout negeert en doorgaat of afbreekt zult u opnieuw moeten vergelijken!
+different
+verschillend
+file exists on both sides
+Bestand bestaat aan beide zijde
+on one side only
+alleen aan één kant
+|> file on right side only\n
+|> Bestand bestaat alleen aan de rechter kant\n
diff --git a/french.lng b/french.lng
index 52bc5d87..48824838 100644
--- a/french.lng
+++ b/french.lng
@@ -44,6 +44,8 @@
&Abandon
&About...
&A propos de...
+&Adjust file times
+&Ajuster les dates de fichiers
&Advanced
&Avancé
&Back
@@ -99,7 +101,7 @@
- left newer
- fichier de gauche plus récent
- right
-- à droite
+- à droite
- right newer
- fichier de droite plus récent
- same date (different size)
@@ -112,12 +114,20 @@
-Synchronisation de fichiers Open-Source-
.
,
-1. Enter full file or directory names separated by ';' or a new line.\n2. Use wildcard characters '*' and '?'.
-1. Entrez le nom complet des fichiers ou des dossier séparés par un ';' ou par un 'retour charit'.\n2. Les caractères génériques '*' et '?' sont acceptés.
+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'.
+2. Use wildcard characters '*' and '?'.
+2. Les caractères génériques '*' et '?' sont acceptés.
+3. Exclude files directly on main grid via context menu.
+3. Excluez les fichiers directement sur le tableau principal à l'aide du menu contextuel.
+4. Keep the number of entries small for best performance.
+4. Réduisez le nombre d'entrées pour améliorer les performances.
<< left file is newer\n
<< le fichier de gauche est plus récent\n
<Directory>
<Répertoire>
+<multiple selection>
+<sélection multiple>
<| file on left side only\n
<| Le fichier existe seulement à gauche\n
== files are equal\n\n
@@ -137,13 +147,21 @@ Action
Add folder pair
Ajout d'un couple de dossiers
Add to exclude filter:
-Ajout au filtre exclure:
+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:
+Ajuster les dates de modification de tous les fichiers contenus dans le dossier spécifié et ses sous-dossiers. Ce règlage manuel pourrait s'avérer nécessaire si vous synchroniser de nouveau un lecteur en FAT32 avec l'option heure d'été sectionnée. Pour plus d'informations, lire cet article :
+All file times have been adjusted successfully!
+Toutes les dates de fichiers ont été ajustées avec succès!
All items have been synchronized!
Tous les éléments ont été synchronisés!
An error occured
Une erreur s'est produite
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:
@@ -173,7 +191,7 @@ Comparaison par...
Comparing content
Comparaison du contenu
Comparing content of files
-Comparaison du contenu des fichiers en cours
+Comparaison du contenu des fichiers en cours
Comparing...
Comparaison en cours...
Completed
@@ -212,22 +230,20 @@ Copy to clipboard\tCTRL+C
Copier dans le presse-papiers\tCTRL+C
Copying file
Copie du fichier en cours
-Could not create file
-Impossible de créer le fichier
Could not open configuration file
-Ipossible d'ouvrir le fichier de configuration
+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 :
+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
+Erreur en écriture sur
Create a batch job
Création du fichier de commandes
Create:
@@ -258,8 +274,8 @@ Deleting file
Suppression du fichier
Deleting folder
Suppression du répertoire
-Directory does not exist. Please select a new one:
-Le répertoire n'existe pas. Veuillez en choisir un autre:
+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 nothing
@@ -277,27 +293,31 @@ Email:
Error
Erreur
Error adapting modification time of file
-Erreur lors de la modification de la date du fichier
+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
+Erreur lors de la copie du fichier
Error creating directory
-Erreur lors de la création du répertoire
+Erreur lors de la création du répertoire
Error deleting directory
-Erreur lors de la suppression du répertoire
+Erreur lors de la suppression du répertoire
Error deleting file
-Erreur lors de la suppression du fichier
-Error moving file to recycle bin:
-Erreur lors du déplacement du fichier vers la corbeille:
+Erreur lors de la suppression du 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
+Erreur lors de l'analyse du fichier de configuration
Error reading file:
Erreur lors de la lecture du fichier:
+Error scanning directory:
+Erreur lors du parcours du répertoire:
Error traversing directory
-Erreur lors du parcours du répertoire
+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
@@ -324,8 +344,8 @@ Filename
Nom du fichier
Files are found equal if\n - file content\nis the same.
Les fichiers sont considérés comme identiques, si\n - leur contenu est identique.
-Files are found equal if\n - filesize\n - last write time (UTC) and date\nare the same.
-Les fichiers sont considérés comme identiques, si\n - leur taille\n - leur date et heure(UTC) sont identiques.
+Files are found equal if\n - filesize\n - last write time and date\nare the same.
+Les fichiers sont considérés comme identiques, si\n - leur taille\n - leur date et heure sont identiques.
Files remaining:
Fichiers restants:
Files that exist on both sides and have different content
@@ -347,7 +367,7 @@ Fichiers/répertoires existants seulement à droite
Filter
Filtrage
Filter active: Press again to deactivate
-Filtrage actif: Cliquez de nouveau pour le désactiver
+Filtrage actif: Cliquez de nouveau pour le désactiver
Filter files
Filtrage des fichiers
Filter view
@@ -368,6 +388,18 @@ FreeFileSync configuration
FreeFileSync configuration
Help
Aide
+Hide files that are different
+Masquer les fichiers différents
+Hide files that are equal
+Masquer les fichiers identiques
+Hide files that are newer on left
+Masquer les fichiers plus récents à gauche
+Hide files that are newer on right
+Masquer les fichiers plus récents à droite
+Hide files that exist on left side only
+Masquer les fichiers existant des deux côtés
+Hide files that exist on right side only
+Masquer les fichiers n'existant qu'à droite
Hide filtered items
Masquer les éléments filtrés
Hide further error messages during the current process and continue
@@ -407,7 +439,7 @@ Messages log:\n---------------
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é:
+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!
@@ -455,11 +487,13 @@ Enregistrer la configuration courante
Saved aborted!
Enregistrement annulé!
Scanning
-Lecture en cours
+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
@@ -508,6 +542,8 @@ Synchronize both sides simultaneously: Copy new or updated files in both directi
Synchronisation simultanée des deux côtés. Copie des fichiers nouveaux ou mis à jour.
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 anymore!
@@ -516,10 +552,12 @@ This variant evaluates two equally named files as being equal when they have the
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:
Temps écoulé:
+Time shift in seconds
+Décalage horaire en secondes
Total amount of data that will be transferred
Volume de données à transférer
Total time:
-Temps total:
+Temps total:
Two way <->
Des 2 côtés <->
Unable to create logfile!
@@ -535,7 +573,7 @@ Utilisation de la corbeille lors de la suppression ou du remplacement des fichie
Warning
Attention
Warning: Synchronization failed for
-Attention : la synchronisation a échoué à cause de
+Attention : la synchronisation a échoué à cause de
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é:
\n\nContinue with next object, retry or abort comparison?
diff --git a/german.lng b/german.lng
index 5f2161ac..d5d6bc40 100644
--- a/german.lng
+++ b/german.lng
@@ -44,6 +44,8 @@
&Abbruch
&About...
&Über...
+&Adjust file times
+&Dateizeiten ändern
&Advanced
&Erweitert
&Back
@@ -112,12 +114,20 @@
-Open-Source Datei-Synchronisation-
.
,
-1. Enter full file or directory names separated by ';' or a new line.\n2. Use wildcard characters '*' and '?'.
-1. Komplette Datei- und Verzeichnisnamen getrennt durch ';' oder eine Neuzeile eingeben.\n2. Die Platzhalter '*' und '?' werden unterstützt.
+1. Enter full file or directory names separated by ';' or a new line.
+1. Komplette Datei- und Verzeichnisnamen getrennt durch ';' oder eine Neuzeile eingeben.
+2. Use wildcard characters '*' and '?'.
+2. Die Platzhalter '*' und '?' werden unterstützt.
+3. Exclude files directly on main grid via context menu.
+3. Dateien können direkt über das Kontextmenü im Hauptfenster ausgeschlossen werden.
+4. Keep the number of entries small for best performance.
+4. Für beste Performance möglichst wenige Einträge filtern.
<< left file is newer\n
<< linke Datei ist neuer\n
<Directory>
<Verzeichnis>
+<multiple selection>
+<Mehrfachauswahl>
<| file on left side only\n
<| Datei existiert nur links\n
== files are equal\n\n
@@ -138,12 +148,20 @@ Add folder pair
Verzeichnispaar hinzufügen
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:
+Passt die Änderungszeiten aller Datein im angegebenen Ordner einschließlich Unterordner an. Diese manuelle Änderung kann nötig sein, wenn gegen ein FAT32-Laufwerk synchronisiert und zwischen Sommer- und Winterzeit umgestellt wurde. Für eine Übersicht der Problematik siehe:
+All file times have been adjusted successfully!
+Alle Dateien wurden erfolgreich angepasst!
All items have been synchronized!
Alle Elemente wurden synchronisiert!
An error occured
Fehler
An exception occured!
Eine Exception wurde geworfen!
+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:
@@ -212,8 +230,6 @@ Copy to clipboard\tCTRL+C
Kopiere in Zwischenablage\tCTRL+C
Copying file
Kopiere Datei
-Could not create file
-Fehler beim Erstellen der Datei
Could not open configuration file
Fehler beim Öffnen der Datei
Could not open file:
@@ -258,8 +274,8 @@ Deleting file
Lösche Datei
Deleting folder
Lösche Verzeichnis
-Directory does not exist. Please select a new one:
-Das Verzeichnis existiert nicht. Bitte ein anderes auswählen:
+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 nothing
@@ -278,6 +294,8 @@ 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
@@ -290,12 +308,14 @@ Error deleting directory
Fehler beim Löschen des Verzeichnisses
Error deleting file
Fehler beim Löschen der Datei
-Error moving file to recycle bin:
-Fehler beim Verschieben der Datei in den Papierkorb:
+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 scanning directory:
+Fehler beim Lesen des Verzeichnisses:
Error traversing directory
Fehler beim Durchsuchen des Verzeichnisses
Error when converting int to wxString
@@ -324,8 +344,8 @@ Filename
Dateiname
Files are found equal if\n - file content\nis the same.
Dateien gelten als gleich, wenn\n - der Inhalt\ngleich ist.
-Files are found equal if\n - filesize\n - last write time (UTC) and date\nare the same.
-Dateien gelten als gleich, wenn\n - die Größe\n - Datum und Uhrzeit(UTC) der letzten Änderung\ngleich sind.
+Files are found equal if\n - filesize\n - last write time and date\nare the same.
+Dateien gelten als gleich, wenn\n - die Größe\n - Datum und Uhrzeit der letzten Änderung\ngleich sind.
Files remaining:
Verbliebene Dateien:
Files that exist on both sides and have different content
@@ -368,6 +388,18 @@ FreeFileSync configuration
FreeFileSync Konfiguration
Help
Hilfe
+Hide files that are different
+Blende unterschiedliche Dateien aus
+Hide files that are equal
+Blende gleiche Dateien aus
+Hide files that are newer on left
+Blende Dateien aus, die auf beiden Seiten existieren; linke Datei ist neuer
+Hide files that are newer on right
+Blende Dateien aus, die auf beiden Seiten existieren; rechte Datei ist neuer
+Hide files that exist on left side only
+Blende Dateien aus, die nur links existieren
+Hide files that exist on right side only
+Blende Dateien aus, die nur rechts existieren
Hide filtered items
Gefilterte Elemente ausblenden
Hide further error messages during the current process and continue
@@ -460,6 +492,8 @@ Scanning...
Suche Dateien...
Select a folder
Verzeichnis wählen
+Select folder
+Verzeichnis auswählen
Select variant:
Variante auswählen:
Set filter for synchronization
@@ -508,6 +542,8 @@ Synchronize both sides simultaneously: Copy new or updated files in both directi
Beide Seiten gleichzeitig synchronisieren: Neue oder aktualisierte Dateien werden auf die jeweils andere Seite kopiert.
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 anymore!
@@ -516,6 +552,8 @@ This variant evaluates two equally named files as being equal when they have the
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:
Vergangene Zeit:
+Time shift in seconds
+Zeitverschiebung in Sekunden
Total amount of data that will be transferred
Gesamtmenge der Daten, die übertragen werden
Total time:
diff --git a/japanese.lng b/japanese.lng
index 56d2cd0f..0f3d3d05 100644
--- a/japanese.lng
+++ b/japanese.lng
@@ -31,19 +31,21 @@
of
/
overwriting
- 上書き中
+ 上書き中
row in view
 列を表示
rows in view
 列を表示
to
- から
+ から
!= files are different\n
!= ファイルは異なっています\n
&Abort
情報(&A)
&About...
情報(&A)...
+&Adjust file times
+ファイル時間の調整(&A)
&Advanced
拡張(&A)
&Back
@@ -112,12 +114,20 @@
-Open-Source ファイル同期ツール-
.
,
-1. Enter full file or directory names separated by ';' or a new line.\n2. Use wildcard characters '*' and '?'.
-完全なファイル/ディレクトリ名を ' ; ' で区切って入力してください。\n2.ワイルドカードに ' * ' と ' ? ' を使用出来ます。
+1. Enter full file or directory names separated by ';' or a new line.
+1.完全なファイル/ディレクトリ名を ' ; ' で区切って入力してください。
+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
@@ -137,13 +147,21 @@ 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:
+指定したフォルダとそのサブフォルダに存在する、すべてのファイルの更新時間を調整します。\nFAT32ドライブを同期に使用している場合は、\nここで最適化しておく必要があるかもしれません(夏時間は切り替えられます)\n\n この機能に関する詳細については、こちらをご覧ください:
+All file times have been adjusted successfully!
+ファイルの時間調整が完了しました!
All items have been synchronized!
すべてのアイテムは同期されました!
An error occured
エラーが発生
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:
@@ -211,23 +229,21 @@ Copy from right to left overwriting
Copy to clipboard\tCTRL+C
クリップボードにコピー\tCTRL+C
Copying file
-ファイルをコピー中
-Could not create 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
-書き込みに失敗
+書き込みに失敗
Create a batch job
一括ジョブを作成
Create:
@@ -258,8 +274,8 @@ Deleting file
ファイルを削除中
Deleting folder
フォルダを削除中
-Directory does not exist. Please select a new one:
-ディレクトリが見つかりません。 再度選択してください:
+Directory does not exist:
+ディレクトリが存在しません:
Do not show graphical status and error messages but write to a logfile instead
進捗状況、及びエラーを表示しないで、代わりにログファイルに書き込む
Do nothing
@@ -277,7 +293,9 @@ 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
@@ -287,17 +305,19 @@ Error copying file
Error creating directory
ディレクトリの作成に失敗
Error deleting directory
-ディレクトリの削除に失敗
+ディレクトリの削除に失敗
Error deleting file
-ファイルの削除に失敗
-Error moving file to recycle bin:
-ファイルをゴミ箱に移動できません:
+ファイルの削除に失敗
+Error moving to recycle bin:
+ゴミ箱への移動に失敗しました:
Error parsing configuration file
-構成ファイルの構文に誤りがあります
+構成ファイルの構文に誤りがあります
Error reading file:
ファイル読み込みエラー:
+Error scanning directory:
+ディレクトリの読み込みエラー:
Error traversing directory
-ディレクトリの移動エラー
+ディレクトリの移動エラー
Error when converting int to wxString
wxString の変換エラー
Error when converting wxString to double
@@ -324,8 +344,8 @@ Filename
ファイル名
Files are found equal if\n - file content\nis the same.
ファイルが同様だった場合\n - ファイル内容\nで判断する
-Files are found equal if\n - filesize\n - last write time (UTC) and date\nare the same.
-ファイルが同様だった場合\n - ファイルサイズ\n - 最終書き込み時間(UTC)と日付\nで判断する
+Files are found equal if\n - filesize\n - last write time and date\nare the same.
+ファイルが同様だった場合\n - ファイルサイズ\n - 最終書き込み時間と日付\nで判断する
Files remaining:
残りのファイル:
Files that exist on both sides and have different content
@@ -368,6 +388,18 @@ 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 and continue
@@ -460,6 +492,8 @@ Scanning...
スキャン中...
Select a folder
フォルダを選択
+Select folder
+フォルダ選択
Select variant:
変数を選択:
Set filter for synchronization
@@ -508,6 +542,8 @@ Synchronize both sides simultaneously: Copy new or updated files in both directi
両側を同時に処理: 両方のディレクトリのより新しいファイルをコピー
Synchronizing...
同期処理中...
+System out of memory!
+メモリが不足しています!
The selected file does not contain a valid configuration!
選択されたファイルには有効な構成が含まれていません!
The selected file does not exist anymore!
@@ -516,6 +552,8 @@ This variant evaluates two equally named files as being equal when they have the
この変数では、ふたつの同名ファイルが存在した場合、 それぞれのファイルサイズと最終更新日付/時間を比較します。\nファイル時間の差異が 2 秒以内の場合は検出されないということに注意してください。 (これは、FAT32システムで正確に同期を行うことができる最小値です)
Time elapsed:
経過時間:
+Time shift in seconds
+タイムシフト(秒)
Total amount of data that will be transferred
転送されたデータの総量
Total time:
@@ -535,7 +573,7 @@ Use Recycle Bin when deleting or overwriting files during synchronization
Warning
警告
Warning: Synchronization failed for
-警告: 同期処理に失敗
+警告: 同期処理に失敗
When \"Compare\" is triggered with this option set the following decision tree is processed:
この設定で \"比較\" トリガが実行された場合は、以下のツリーに従って処理されていきます。
\n\nContinue with next object, retry or abort comparison?
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp
index 86a121d3..3fdc5967 100644
--- a/library/CustomGrid.cpp
+++ b/library/CustomGrid.cpp
@@ -39,7 +39,8 @@ public:
{
if (gridRefUI)
return max(gridRefUI->size(), MinimumRows);
- return MinimumRows; //grid is initialized with this number of rows
+ else
+ return MinimumRows; //grid is initialized with this number of rows
}
virtual bool IsEmptyCell( int row, int col )
@@ -94,28 +95,28 @@ public:
case 1:
if (col < 4)
{
- if (gridLine.fileDescrLeft.objType == TYPE_DIRECTORY)
+ if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
{
switch (col)
{
case 0: //filename
return wxEmptyString;
case 1: //relative path
- return gridLine.fileDescrLeft.relFilename;
+ return gridLine.fileDescrLeft.relativeName;
case 2: //file size
return _("<Directory>");
case 3: //date
return gridLine.fileDescrLeft.lastWriteTime;
}
}
- else if (gridLine.fileDescrLeft.objType == TYPE_FILE)
+ else if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE)
{
switch (col)
{
case 0: //filename
- return gridLine.fileDescrLeft.relFilename.AfterLast(GlobalResources::fileNameSeparator);
+ return gridLine.fileDescrLeft.relativeName.AfterLast(GlobalResources::fileNameSeparator);
case 1: //relative path
- return gridLine.fileDescrLeft.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
+ return gridLine.fileDescrLeft.relativeName.BeforeLast(GlobalResources::fileNameSeparator);
case 2: //file size
return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrLeft.fileSize.ToString());
case 3: //date
@@ -128,28 +129,28 @@ public:
case 2:
if (col < 4)
{
- if (gridLine.fileDescrRight.objType == TYPE_DIRECTORY)
+ if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
{
switch (col)
{
case 0: //filename
return wxEmptyString;
case 1: //relative path
- return gridLine.fileDescrRight.relFilename;
+ return gridLine.fileDescrRight.relativeName;
case 2: //file size
return _("<Directory>");
case 3: //date
return gridLine.fileDescrRight.lastWriteTime;
}
}
- else if (gridLine.fileDescrRight.objType == TYPE_FILE)
+ else if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE)
{
switch (col)
{
case 0: //filename
- return gridLine.fileDescrRight.relFilename.AfterLast(GlobalResources::fileNameSeparator);
+ return gridLine.fileDescrRight.relativeName.AfterLast(GlobalResources::fileNameSeparator);
case 1: //relative path
- return gridLine.fileDescrRight.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
+ return gridLine.fileDescrRight.relativeName.BeforeLast(GlobalResources::fileNameSeparator);
case 2: //file size
return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrRight.fileSize.ToString());
case 3: //date
@@ -249,9 +250,9 @@ public:
if (!cmpLine.selectedForSynchronization)
return BLUE;
//mark directories
- else if (gridIdentifier == 1 && cmpLine.fileDescrLeft.objType == TYPE_DIRECTORY)
+ else if (gridIdentifier == 1 && cmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
return GREY;
- else if (gridIdentifier == 2 && cmpLine.fileDescrRight.objType == TYPE_DIRECTORY)
+ else if (gridIdentifier == 2 && cmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
return GREY;
else
return NONE;
diff --git a/library/CustomGrid.h b/library/CustomGrid.h
index 0679c6c7..8f22275b 100644
--- a/library/CustomGrid.h
+++ b/library/CustomGrid.h
@@ -44,7 +44,7 @@ public:
//set sort direction indicator on UI
void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap);
- void DrawColLabel( wxDC& dc, int col );
+ void DrawColLabel(wxDC& dc, int col);
private:
void adjustGridHeights();
diff --git a/library/globalFunctions.cpp b/library/globalFunctions.cpp
index 67b56819..07c34af0 100644
--- a/library/globalFunctions.cpp
+++ b/library/globalFunctions.cpp
@@ -1,5 +1,8 @@
#include "globalFunctions.h"
#include "resources.h"
+#include <wx/msgdlg.h>
+#include <wx/file.h>
+
inline
int globalFunctions::round(const double d)
@@ -123,3 +126,76 @@ void globalFunctions::writeInt(wxOutputStream& stream, const int number)
const char* buffer = reinterpret_cast<const char*>(&number);
stream.Write(buffer, sizeof(int));
}
+
+
+//############################################################################
+Performance::Performance() :
+ resultWasShown(false)
+{
+ timer.Start();
+}
+
+
+Performance::~Performance()
+{
+ if (!resultWasShown)
+ showResult();
+}
+
+
+void Performance::showResult()
+{
+ resultWasShown = true;
+ wxMessageBox(globalFunctions::numberToWxString(unsigned(timer.Time())) + wxT(" ms"));
+ timer.Start(); //reset timer
+}
+
+
+//############################################################################
+DebugLog::DebugLog() :
+ lineCount(0),
+ logFile(NULL)
+{
+ logFile = new wxFile;
+ logfileName = assembleFileName();
+ logFile->Open(logfileName.c_str(), wxFile::write);
+}
+
+
+DebugLog::~DebugLog()
+{
+ delete logFile; //automatically closes file handle
+}
+
+
+wxString DebugLog::assembleFileName()
+{
+ wxString tmp = wxDateTime::Now().FormatISOTime();
+ tmp.Replace(wxT(":"), wxEmptyString);
+ return wxString(wxT("DEBUG_")) + wxDateTime::Now().FormatISODate() + wxChar('_') + tmp + wxT(".log");
+}
+
+
+void DebugLog::write(const wxString& logText)
+{
+ ++lineCount;
+ if (lineCount % 10000 == 0) //prevent logfile from becoming too big
+ {
+ logFile->Close();
+ wxRemoveFile(logfileName);
+
+ logfileName = assembleFileName();
+ logFile->Open(logfileName.c_str(), wxFile::write);
+ }
+
+ logFile->Write(wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] "));
+ logFile->Write(logText + wxChar('\n'));
+}
+
+//DebugLog logDebugInfo;
+
+
+wxString getCodeLocation(const wxString file, const int line)
+{
+ return wxString(file).AfterLast(GlobalResources::fileNameSeparator) + wxT(", LINE ") + globalFunctions::numberToWxString(line) + wxT(" | ");
+}
diff --git a/library/globalFunctions.h b/library/globalFunctions.h
index 40eba94f..efbc42c7 100644
--- a/library/globalFunctions.h
+++ b/library/globalFunctions.h
@@ -3,12 +3,15 @@
#include <string>
#include <algorithm>
+#include <vector>
#include <wx/string.h>
#include <fstream>
#include <wx/stream.h>
+#include <wx/stopwatch.h>
using namespace std;
+
namespace globalFunctions
{
int round(double d); //little rounding function
@@ -40,9 +43,54 @@ 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();
}
+//############################################################################
+class Performance
+{
+public:
+ wxDEPRECATED(Performance()); //generates compiler warnings as a reminder to remove code after measurements
+ ~Performance();
+ void showResult();
+
+private:
+ bool resultWasShown;
+ wxStopWatch timer;
+};
+
+//two macros for quick performance measurements
+#define PERF_START Performance a;
+#define PERF_STOP a.showResult();
+
+
+//############################################################################
+class wxFile;
+class DebugLog
+{
+public:
+ wxDEPRECATED(DebugLog());
+ ~DebugLog();
+ void write(const wxString& logText);
+
+private:
+ wxString assembleFileName();
+ wxString logfileName;
+ int lineCount;
+ wxFile* logFile; //logFile.close(); <- not needed
+};
+extern DebugLog logDebugInfo;
+wxString getCodeLocation(const wxString file, const int line);
+
+//small macro for writing debug information into a logfile
+#define WRITE_DEBUG_LOG(x) logDebugInfo.write(getCodeLocation(__TFILE__, __LINE__) + x);
+//speed alternative: wxLogDebug(wxT("text")) + DebugView
+
+
+//############################################################################
class RuntimeException //Exception class used to notify of general runtime exceptions
{
public:
@@ -50,6 +98,7 @@ public:
wxString show() const
{
+
return errorMessage;
}
diff --git a/library/misc.cpp b/library/misc.cpp
index 5fbeb655..0a850805 100644
--- a/library/misc.cpp
+++ b/library/misc.cpp
@@ -1,13 +1,10 @@
#include "misc.h"
-#include <fstream>
#include <wx/msgdlg.h>
#include "resources.h"
#include "globalFunctions.h"
-const string CustomLocale::FfsLanguageDat = "language.dat";
-
-
+inline
void exchangeEscapeChars(wxString& data)
{
wxString output;
@@ -59,41 +56,7 @@ CustomLocale::CustomLocale() :
{}
-CustomLocale::~CustomLocale()
-{
- //write language to file
- ofstream output(FfsLanguageDat.c_str());
- if (output)
- {
- globalFunctions::writeInt(output, currentLanguage);
- output.close();
- }
- else
- wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + wxString::From8BitData(FfsLanguageDat.c_str()) + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR);
-}
-
-
-void CustomLocale::loadLanguageFromCfg() //retrieve language from config file: do NOT put into constructor since working directory has not been set!
-{
- int language = wxLANGUAGE_ENGLISH;
-
- //try to load language setting from file
- ifstream input(FfsLanguageDat.c_str());
- if (input)
- {
- language = globalFunctions::readInt(input);
- input.close();
- }
- else
- language = wxLocale::GetSystemLanguage();
-
- wxLocale::Init(language, wxLOCALE_LOAD_DEFAULT | wxLOCALE_CONV_ENCODING);
-
- loadLanguageFile(language);
-}
-
-
-void CustomLocale::loadLanguageFile(int language)
+void CustomLocale::setLanguage(const int language)
{
currentLanguage = language;
@@ -109,11 +72,21 @@ void CustomLocale::loadLanguageFile(int language)
case wxLANGUAGE_JAPANESE:
languageFile = "japanese.lng";
break;
+ case wxLANGUAGE_DUTCH:
+ languageFile = "dutch.lng";
+ break;
default:
languageFile.clear();
currentLanguage = wxLANGUAGE_ENGLISH;
}
+ static bool initialized = false; //wxLocale is a "static" too!
+ if (!initialized)
+ {
+ initialized = true;
+ wxLocale::Init(currentLanguage, wxLOCALE_LOAD_DEFAULT | wxLOCALE_CONV_ENCODING);
+ }
+
//load language file into buffer
translationDB.clear();
const int bufferSize = 100000;
@@ -123,7 +96,6 @@ void CustomLocale::loadLanguageFile(int language)
ifstream langFile(languageFile.c_str(), ios::binary);
if (langFile)
{
- int rowNumber = 0;
TranslationLine currentLine;
//Delimiter:
@@ -131,7 +103,7 @@ void CustomLocale::loadLanguageFile(int language)
//Linux: 0xa \n
//Mac: 0xd \r
//Win: 0xd 0xa \r\n <- language files are in Windows format
- while (langFile.getline(temp, bufferSize, 0xd)) //specify delimiter explicitly
+ for (int rowNumber = 0; langFile.getline(temp, bufferSize, 0xd); ++rowNumber) //specify delimiter explicitly
{
langFile.get(); //discard the 0xa character
@@ -147,7 +119,6 @@ void CustomLocale::loadLanguageFile(int language)
currentLine.translation = formattedString;
translationDB.insert(currentLine);
}
- ++rowNumber;
}
langFile.close();
}
@@ -155,7 +126,7 @@ void CustomLocale::loadLanguageFile(int language)
wxMessageBox(wxString(_("Could not read language file ")) + wxT("\"") + wxString(languageFile.c_str(), wxConvUTF8) + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR);
}
else
- ; //if languageFile is empty language is defaulted to english
+ ; //if languageFile is empty texts will be english per default
//these global variables need to be redetermined on language selection
GlobalResources::decimalPoint = _(".");
@@ -175,4 +146,3 @@ const wxChar* CustomLocale::GetString(const wxChar* szOrigString, const wxChar*
//fallback
return (szOrigString);
}
-
diff --git a/library/misc.h b/library/misc.h
index 68a5db68..5fa2c943 100644
--- a/library/misc.h
+++ b/library/misc.h
@@ -4,6 +4,7 @@
#include <wx/string.h>
#include <set>
#include <wx/intl.h>
+#include <wx/panel.h>
using namespace std;
@@ -32,12 +33,9 @@ class CustomLocale : public wxLocale
{
public:
CustomLocale();
+ ~CustomLocale() {}
- ~CustomLocale();
-
- void loadLanguageFromCfg();
-
- void loadLanguageFile(int language);
+ void setLanguage(const int language);
int getLanguage()
{
@@ -53,4 +51,5 @@ private:
int currentLanguage;
};
+
#endif // MISC_H_INCLUDED
diff --git a/library/multithreading.cpp b/library/multithreading.cpp
index 78077f1e..753e6651 100644
--- a/library/multithreading.cpp
+++ b/library/multithreading.cpp
@@ -168,7 +168,7 @@ void UpdateWhileExecuting::waitUntilReady()
}
// /|\ \|/ must be called directly after each other
-void UpdateWhileExecuting::execute(StatusUpdater* statusUpdater)
+void UpdateWhileExecuting::execute(StatusHandler* statusUpdater)
{
readyToReceiveResult.Lock();
@@ -179,8 +179,8 @@ void UpdateWhileExecuting::execute(StatusUpdater* statusUpdater)
{
statusUpdater->requestUiRefresh(true); //ATTENTION: Exception "AbortThisProcess" may be thrown here!!!
- if (workDone == true) //workaround for a bug in wxWidgets v2.8.9 class wxCondition: signals might get lost
- break; //no mutex for workDone needed here: it is changed only when mainthread is in WaitTimeout()
+ if (workDone) //workaround for a bug in wxWidgets v2.8.9 class wxCondition: signals might get lost
+ break; //no mutex for workDone needed here: it is changed only when mainthread is in WaitTimeout()
}
}
diff --git a/library/multithreading.h b/library/multithreading.h
index 161fd687..68ad7492 100644
--- a/library/multithreading.h
+++ b/library/multithreading.h
@@ -1,55 +1,7 @@
#ifndef MULTITHREADING_H_INCLUDED
#define MULTITHREADING_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
-
-bool updateUiIsAllowed(); //test if a specific amount of time is over
-void updateUiNow(); //do the updating
-
-
-//interface for status updates (can be implemented by UI or commandline)
-//overwrite virtual methods for respective functionality
-class StatusUpdater
-{
-public:
- StatusUpdater() :
- abortionRequested(false) {}
- virtual ~StatusUpdater() {}
-
- //these methods have to be implemented in the derived classes to handle error and status information
- virtual void updateStatusText(const wxString& text) = 0;
- virtual void initNewProcess(int objectsTotal, double dataTotal, int processID) = 0; //informs about the total amount of data that will be processed from now on
- virtual void updateProcessedData(int objectsProcessed, double dataProcessed) = 0; //called periodically after data was processed
- virtual int reportError(const wxString& text) = 0;
-
- //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
- virtual void forceUiRefresh() = 0;
- void requestUiRefresh(bool asyncProcessActive = false)
- {
- if (updateUiIsAllowed()) //test if specific time span between ui updates is over
- forceUiRefresh();
-
- if (abortionRequested && !asyncProcessActive)
- abortThisProcess(); //abort can be triggered by requestAbortion()
- }
-
- void requestAbortion() //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
- { //currently used by the UI status information screen, when button "Abort is pressed"
- abortionRequested = true;
- }
-
- static const int continueNext = -1;
- static const int retry = -2;
-
-protected:
- virtual void abortThisProcess() = 0;
-
- bool abortionRequested;
-};
-
+#include "statusHandler.h"
class WorkerThread;
@@ -65,7 +17,7 @@ public:
virtual ~UpdateWhileExecuting();
void waitUntilReady();
- void execute(StatusUpdater* statusUpdater);
+ void execute(StatusHandler* statusUpdater);
private:
diff --git a/library/processXml.cpp b/library/processXml.cpp
index 80f284c2..e87ae9de 100644
--- a/library/processXml.cpp
+++ b/library/processXml.cpp
@@ -1,11 +1,75 @@
#include "processXml.h"
#include <wx/filefn.h>
#include <wx/ffile.h>
+#include <wx/intl.h>
#include "globalFunctions.h"
using namespace globalFunctions;
using namespace xmlAccess;
+//small helper functions
+bool readXmlElementValue(string& output, const TiXmlElement* parent, const string& name);
+bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& name);
+bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name);
+bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const string& name);
+bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name);
+
+void addXmlElement(TiXmlElement* parent, const string& name, const string& value);
+void addXmlElement(TiXmlElement* parent, const string& name, const int value);
+void addXmlElement(TiXmlElement* parent, const string& name, const SyncConfiguration::Direction value);
+void addXmlElement(TiXmlElement* parent, const string& name, const bool value);
+
+
+class XmlConfigInput
+{
+public:
+ XmlConfigInput(const wxString& fileName, const XmlType type);
+ ~XmlConfigInput() {}
+
+ bool loadedSuccessfully()
+ {
+ return loadSuccess;
+ }
+
+ //read gui settings, all values retrieved are optional, so check for initial values! (== -1)
+ bool readXmlGuiConfig(XmlGuiConfig& outputCfg);
+ //read batch settings, all values retrieved are optional
+ bool readXmlBatchConfig(XmlBatchConfig& outputCfg);
+ //read global settings, valid for both GUI and batch mode, independent from configuration
+ bool readXmlGlobalSettings(XmlGlobalSettings& outputCfg);
+
+private:
+ //read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully
+ bool readXmlMainConfig(MainConfiguration& mainCfg, vector<FolderPair>& directoryPairs);
+
+ TiXmlDocument doc;
+ bool loadSuccess;
+};
+
+
+class XmlConfigOutput
+{
+public:
+ XmlConfigOutput(const wxString& fileName, const XmlType type);
+ ~XmlConfigOutput() {}
+
+ bool writeToFile();
+
+ //write gui settings
+ bool writeXmlGuiConfig(const XmlGuiConfig& inputCfg);
+ //write batch settings
+ bool writeXmlBatchConfig(const XmlBatchConfig& inputCfg);
+ //write global settings
+ bool writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg);
+
+private:
+ //write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully
+ bool writeXmlMainConfig(const MainConfiguration& mainCfg, const vector<FolderPair>& directoryPairs);
+
+ TiXmlDocument doc;
+ const wxString& m_fileName;
+};
+
XmlType xmlAccess::getXmlType(const wxString& filename)
{
@@ -36,12 +100,101 @@ XmlType xmlAccess::getXmlType(const wxString& filename)
return XML_BATCH_CONFIG;
else if (string(cfgType) == "GUI")
return XML_GUI_CONFIG;
+ else if (string(cfgType) == "GLOBAL")
+ return XML_GLOBAL_SETTINGS;
else
return XML_OTHER;
}
-XmlInput::XmlInput(const wxString& fileName, const XmlType type) :
+XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename)
+{
+ //load XML
+ XmlConfigInput inputFile(filename, XML_GUI_CONFIG);
+
+ XmlGuiConfig outputCfg;
+
+ if (!inputFile.loadedSuccessfully())
+ throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""));
+
+ if (!inputFile.readXmlGuiConfig(outputCfg)) //read GUI layout configuration
+ throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""));
+
+ return outputCfg;
+}
+
+
+XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename)
+{
+ //load XML
+ XmlConfigInput inputFile(filename, XML_BATCH_CONFIG);
+
+ XmlBatchConfig outputCfg;
+
+ if (!inputFile.loadedSuccessfully())
+ throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""));
+
+ if (!inputFile.readXmlBatchConfig(outputCfg))
+ throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""));
+
+ return outputCfg;
+}
+
+
+XmlGlobalSettings xmlAccess::readGlobalSettings()
+{
+ //load XML
+ XmlConfigInput inputFile(FreeFileSync::FfsGlobalSettingsFile, XML_GLOBAL_SETTINGS);
+
+ XmlGlobalSettings outputCfg;
+
+ if (!inputFile.loadedSuccessfully())
+ throw FileError(wxString(_("Could not open configuration file ")) + wxT("\"") + FreeFileSync::FfsGlobalSettingsFile + wxT("\""));
+
+ if (!inputFile.readXmlGlobalSettings(outputCfg))
+ throw FileError(wxString(_("Error parsing configuration file ")) + wxT("\"") + FreeFileSync::FfsGlobalSettingsFile + wxT("\""));
+
+ return outputCfg;
+}
+
+
+void xmlAccess::writeGuiConfig(const wxString& filename, const XmlGuiConfig& inputCfg)
+{
+ XmlConfigOutput outputFile(filename, XML_GUI_CONFIG);
+
+ //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("\""));
+ return;
+}
+
+
+void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig& inputCfg)
+{
+ XmlConfigOutput outputFile(filename, XML_BATCH_CONFIG);
+
+ //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("\""));
+ return;
+}
+
+
+void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& inputCfg)
+{
+ XmlConfigOutput outputFile(FreeFileSync::FfsGlobalSettingsFile, XML_GLOBAL_SETTINGS);
+
+ //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::FfsGlobalSettingsFile + wxT("\""));
+ return;
+}
+
+
+XmlConfigInput::XmlConfigInput(const wxString& fileName, const XmlType type) :
loadSuccess(false)
{
if (!wxFileExists(fileName)) //avoid wxWidgets error message when wxFFile receives not existing file
@@ -68,6 +221,8 @@ XmlInput::XmlInput(const wxString& fileName, const XmlType type) :
loadSuccess = string(cfgType) == "GUI";
else if (type == XML_BATCH_CONFIG)
loadSuccess = string(cfgType) == "BATCH";
+ else if (type == XML_GLOBAL_SETTINGS)
+ loadSuccess = string(cfgType) == "GLOBAL";
}
}
}
@@ -75,7 +230,7 @@ XmlInput::XmlInput(const wxString& fileName, const XmlType type) :
}
-bool XmlInput::readXmlElementValue(string& output, const TiXmlElement* parent, const string& name)
+bool readXmlElementValue(string& output, const TiXmlElement* parent, const string& name)
{
if (parent)
{
@@ -95,7 +250,7 @@ bool XmlInput::readXmlElementValue(string& output, const TiXmlElement* parent, c
}
-bool XmlInput::readXmlElementValue(int& output, const TiXmlElement* parent, const string& name)
+bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& name)
{
string temp;
if (readXmlElementValue(temp, parent, name))
@@ -108,7 +263,7 @@ bool XmlInput::readXmlElementValue(int& output, const TiXmlElement* parent, cons
}
-bool XmlInput::readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name)
+bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name)
{
int dummy = 0;
if (readXmlElementValue(dummy, parent, name))
@@ -121,17 +276,17 @@ bool XmlInput::readXmlElementValue(CompareVariant& output, const TiXmlElement* p
}
-bool XmlInput::readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const string& name)
+bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const string& name)
{
string dummy;
if (readXmlElementValue(dummy, parent, name))
{
if (dummy == "left")
- output = SYNC_DIR_LEFT;
+ output = SyncConfiguration::SYNC_DIR_LEFT;
else if (dummy == "right")
- output = SYNC_DIR_RIGHT;
+ output = SyncConfiguration::SYNC_DIR_RIGHT;
else //treat all other input as "none"
- output = SYNC_DIR_NONE;
+ output = SyncConfiguration::SYNC_DIR_NONE;
return true;
}
@@ -140,7 +295,7 @@ bool XmlInput::readXmlElementValue(SyncDirection& output, const TiXmlElement* pa
}
-bool XmlInput::readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name)
+bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name)
{
string dummy;
if (readXmlElementValue(dummy, parent, name))
@@ -153,7 +308,7 @@ bool XmlInput::readXmlElementValue(bool& output, const TiXmlElement* parent, con
}
-bool XmlInput::readXmlMainConfig(XmlMainConfig& outputCfg)
+bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, vector<FolderPair>& directoryPairs)
{
TiXmlElement* root = doc.RootElement();
if (!root) return false;
@@ -171,12 +326,13 @@ bool XmlInput::readXmlMainConfig(XmlMainConfig& outputCfg)
string tempString;
//###########################################################
//read compare variant
- if (!readXmlElementValue(outputCfg.cfg.compareVar, cmpSettings, "Variant")) return false;
+ if (!readXmlElementValue(mainCfg.compareVar, cmpSettings, "Variant")) return false;
//read folder pair(s)
TiXmlElement* folderPair = TiXmlHandle(cmpSettings).FirstChild("Folders").FirstChild("Pair").ToElement();
//read folder pairs
+ directoryPairs.clear();
while (folderPair)
{
FolderPair newPair;
@@ -187,37 +343,42 @@ bool XmlInput::readXmlMainConfig(XmlMainConfig& outputCfg)
if (!readXmlElementValue(tempString, folderPair, "Right")) return false;
newPair.rightDirectory = wxString::FromUTF8(tempString.c_str());
- outputCfg.directoryPairs.push_back(newPair);
+ directoryPairs.push_back(newPair);
folderPair = folderPair->NextSiblingElement();
}
//###########################################################
//read sync configuration
- if (!readXmlElementValue(outputCfg.cfg.syncConfiguration.exLeftSideOnly, syncConfig, "LeftOnly")) return false;
- if (!readXmlElementValue(outputCfg.cfg.syncConfiguration.exRightSideOnly, syncConfig, "RightOnly")) return false;
- if (!readXmlElementValue(outputCfg.cfg.syncConfiguration.leftNewer, syncConfig, "LeftNewer")) return false;
- if (!readXmlElementValue(outputCfg.cfg.syncConfiguration.rightNewer, syncConfig, "RightNewer")) return false;
- if (!readXmlElementValue(outputCfg.cfg.syncConfiguration.different, syncConfig, "Different")) return false;
+ if (!readXmlElementValue(mainCfg.syncConfiguration.exLeftSideOnly, syncConfig, "LeftOnly")) return false;
+ if (!readXmlElementValue(mainCfg.syncConfiguration.exRightSideOnly, syncConfig, "RightOnly")) return false;
+ if (!readXmlElementValue(mainCfg.syncConfiguration.leftNewer, syncConfig, "LeftNewer")) return false;
+ if (!readXmlElementValue(mainCfg.syncConfiguration.rightNewer, syncConfig, "RightNewer")) return false;
+ if (!readXmlElementValue(mainCfg.syncConfiguration.different, syncConfig, "Different")) return false;
//###########################################################
//read filter settings
- if (!readXmlElementValue(outputCfg.cfg.filterIsActive, filter, "Active")) return false;
+ if (!readXmlElementValue(mainCfg.filterIsActive, filter, "Active")) return false;
if (!readXmlElementValue(tempString, filter, "Include")) return false;
- outputCfg.cfg.includeFilter = wxString::FromUTF8(tempString.c_str());
+ mainCfg.includeFilter = wxString::FromUTF8(tempString.c_str());
if (!readXmlElementValue(tempString, filter, "Exclude")) return false;
- outputCfg.cfg.excludeFilter = wxString::FromUTF8(tempString.c_str());
+ mainCfg.excludeFilter = wxString::FromUTF8(tempString.c_str());
//###########################################################
//other
- if (!readXmlElementValue(outputCfg.cfg.useRecycleBin, miscSettings, "Recycler")) return false;
- if (!readXmlElementValue(outputCfg.cfg.continueOnError, miscSettings, "Continue")) return false;
+ if (!readXmlElementValue(mainCfg.useRecycleBin, miscSettings, "Recycler")) return false;
+ if (!readXmlElementValue(mainCfg.continueOnError, miscSettings, "Continue")) return false;
return true;
}
-bool XmlInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
+bool XmlConfigInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
{
+ //read main config
+ if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
+ return false;
+
+ //read GUI specific config data
TiXmlElement* root = doc.RootElement();
if (!root) return false;
@@ -229,18 +390,61 @@ bool XmlInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
{
if (!readXmlElementValue(outputCfg.hideFilteredElements, mainWindow, "HideFiltered"))
outputCfg.hideFilteredElements = false;
+ }
+
+ return true;
+}
+
+bool XmlConfigInput::readXmlBatchConfig(XmlBatchConfig& outputCfg)
+{
+ //read main config
+ if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
+ return false;
+
+ //read batch specific config
+ TiXmlElement* root = doc.RootElement();
+ if (!root) return false;
+
+ TiXmlHandle hRoot(root);
+
+ //read batch settings
+ TiXmlElement* batchConfig = hRoot.FirstChild("BatchConfig").ToElement();
+ if (batchConfig)
+ {
//read application window size and position
- if (!readXmlElementValue(outputCfg.widthNotMaximized, mainWindow, "Width"))
- outputCfg.widthNotMaximized = -1;
- if (!readXmlElementValue(outputCfg.heightNotMaximized, mainWindow, "Height"))
- outputCfg.heightNotMaximized = -1;
- if (!readXmlElementValue(outputCfg.posXNotMaximized, mainWindow, "PosX"))
- outputCfg.posXNotMaximized = -1;
- if (!readXmlElementValue(outputCfg.posYNotMaximized, mainWindow, "PosY"))
- outputCfg.posYNotMaximized = -1;
- if (!readXmlElementValue(outputCfg.isMaximized, mainWindow, "Maximized"))
- outputCfg.isMaximized = false;
+ if (!readXmlElementValue(outputCfg.silent, batchConfig, "Silent"))
+ outputCfg.silent = false;
+ }
+
+ return true;
+}
+
+
+bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
+{
+ TiXmlElement* root = doc.RootElement();
+ if (!root) return false;
+
+ TiXmlHandle hRoot(root);
+
+ //read global settings
+ TiXmlElement* global = hRoot.FirstChild("Global").ToElement();
+ if (!global) return false;
+
+ //program language
+ readXmlElementValue(outputCfg.global.programLanguage, global, "Language");
+
+ //gui specific global settings (optional)
+ TiXmlElement* mainWindow = hRoot.FirstChild("Gui").FirstChild("Windows").FirstChild("Main").ToElement();
+ if (mainWindow)
+ {
+ //read application window size and position
+ readXmlElementValue(outputCfg.gui.widthNotMaximized, mainWindow, "Width");
+ readXmlElementValue(outputCfg.gui.heightNotMaximized, mainWindow, "Height");
+ readXmlElementValue(outputCfg.gui.posXNotMaximized, mainWindow, "PosX");
+ readXmlElementValue(outputCfg.gui.posYNotMaximized, mainWindow, "PosY");
+ readXmlElementValue(outputCfg.gui.isMaximized, mainWindow, "Maximized");
//###########################################################
//read column widths
@@ -249,7 +453,7 @@ bool XmlInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
{
const char* width = leftColumn->GetText();
if (width) //may be NULL!!
- outputCfg.columnWidthLeft.push_back(stringToInt(width));
+ outputCfg.gui.columnWidthLeft.push_back(stringToInt(width));
else
break;
@@ -261,7 +465,7 @@ bool XmlInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
{
const char* width = rightColumn->GetText();
if (width) //may be NULL!!
- outputCfg.columnWidthRight.push_back(stringToInt(width));
+ outputCfg.gui.columnWidthRight.push_back(stringToInt(width));
else
break;
@@ -269,31 +473,19 @@ bool XmlInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
}
}
- return true;
-}
+//batch specific global settings
+ TiXmlElement* batch = hRoot.FirstChild("Batch").ToElement();
+ if (!batch) return false;
-bool XmlInput::readXmlBatchConfig(XmlBatchConfig& outputCfg)
-{
- TiXmlElement* root = doc.RootElement();
- if (!root) return false;
- TiXmlHandle hRoot(root);
-
- //read batch settings
- TiXmlElement* batchConfig = hRoot.FirstChild("BatchConfig").ToElement();
- if (batchConfig)
- {
- //read application window size and position
- if (!readXmlElementValue(outputCfg.silent, batchConfig, "Silent"))
- outputCfg.silent = false;
- }
+// if (!readXmlElementValue(outputCfg.dummy, global, "Language")) return false;
return true;
}
-XmlOutput::XmlOutput(const wxString& fileName, const XmlType type) :
+XmlConfigOutput::XmlConfigOutput(const wxString& fileName, const XmlType type) :
m_fileName(fileName)
{
TiXmlBase::SetCondenseWhiteSpace(false); //do not condense whitespace characters
@@ -306,13 +498,15 @@ XmlOutput::XmlOutput(const wxString& fileName, const XmlType type) :
root->SetAttribute("XmlType", "GUI"); //xml configuration type
else if (type == XML_BATCH_CONFIG)
root->SetAttribute("XmlType", "BATCH");
+ else if (type == XML_GLOBAL_SETTINGS)
+ root->SetAttribute("XmlType", "GLOBAL");
else
assert(false);
doc.LinkEndChild(root);
}
-bool XmlOutput::writeToFile()
+bool XmlConfigOutput::writeToFile()
{
//workaround to get a FILE* from a unicode filename
wxFFile dummyFile(m_fileName, wxT("wb"));
@@ -325,7 +519,7 @@ bool XmlOutput::writeToFile()
}
-void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const string& value)
+void addXmlElement(TiXmlElement* parent, const string& name, const string& value)
{
if (parent)
{
@@ -336,26 +530,26 @@ void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const st
}
-void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const int value)
+void addXmlElement(TiXmlElement* parent, const string& name, const int value)
{
addXmlElement(parent, name, numberToString(value));
}
-void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const SyncDirection value)
+void addXmlElement(TiXmlElement* parent, const string& name, const SyncConfiguration::Direction value)
{
- if (value == SYNC_DIR_LEFT)
+ if (value == SyncConfiguration::SYNC_DIR_LEFT)
addXmlElement(parent, name, string("left"));
- else if (value == SYNC_DIR_RIGHT)
+ else if (value == SyncConfiguration::SYNC_DIR_RIGHT)
addXmlElement(parent, name, string("right"));
- else if (value == SYNC_DIR_NONE)
+ else if (value == SyncConfiguration::SYNC_DIR_NONE)
addXmlElement(parent, name, string("none"));
else
assert(false);
}
-void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const bool value)
+void addXmlElement(TiXmlElement* parent, const string& name, const bool value)
{
if (value)
addXmlElement(parent, name, string("true"));
@@ -364,7 +558,7 @@ void XmlOutput::addXmlElement(TiXmlElement* parent, const string& name, const bo
}
-bool XmlOutput::writeXmlMainConfig(const XmlMainConfig& inputCfg)
+bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const vector<FolderPair>& directoryPairs)
{
TiXmlElement* root = doc.RootElement();
if (!root) return false;
@@ -377,14 +571,14 @@ bool XmlOutput::writeXmlMainConfig(const XmlMainConfig& inputCfg)
settings->LinkEndChild(cmpSettings);
//write compare algorithm
- addXmlElement(cmpSettings, "Variant", inputCfg.cfg.compareVar);
+ addXmlElement(cmpSettings, "Variant", mainCfg.compareVar);
//write folder pair(s)
TiXmlElement* folders = new TiXmlElement("Folders");
cmpSettings->LinkEndChild(folders);
//write folder pairs
- for (vector<FolderPair>::const_iterator i = inputCfg.directoryPairs.begin(); i != inputCfg.directoryPairs.end(); ++i)
+ for (vector<FolderPair>::const_iterator i = directoryPairs.begin(); i != directoryPairs.end(); ++i)
{
TiXmlElement* folderPair = new TiXmlElement("Pair");
folders->LinkEndChild(folderPair);
@@ -401,11 +595,11 @@ bool XmlOutput::writeXmlMainConfig(const XmlMainConfig& inputCfg)
TiXmlElement* syncConfig = new TiXmlElement("Directions");
syncSettings->LinkEndChild(syncConfig);
- addXmlElement(syncConfig, "LeftOnly", inputCfg.cfg.syncConfiguration.exLeftSideOnly);
- addXmlElement(syncConfig, "RightOnly", inputCfg.cfg.syncConfiguration.exRightSideOnly);
- addXmlElement(syncConfig, "LeftNewer", inputCfg.cfg.syncConfiguration.leftNewer);
- addXmlElement(syncConfig, "RightNewer", inputCfg.cfg.syncConfiguration.rightNewer);
- addXmlElement(syncConfig, "Different", inputCfg.cfg.syncConfiguration.different);
+ addXmlElement(syncConfig, "LeftOnly", mainCfg.syncConfiguration.exLeftSideOnly);
+ addXmlElement(syncConfig, "RightOnly", mainCfg.syncConfiguration.exRightSideOnly);
+ addXmlElement(syncConfig, "LeftNewer", mainCfg.syncConfiguration.leftNewer);
+ addXmlElement(syncConfig, "RightNewer", mainCfg.syncConfiguration.rightNewer);
+ addXmlElement(syncConfig, "Different", mainCfg.syncConfiguration.different);
//###########################################################
TiXmlElement* miscSettings = new TiXmlElement("Miscellaneous");
@@ -415,21 +609,26 @@ bool XmlOutput::writeXmlMainConfig(const XmlMainConfig& inputCfg)
TiXmlElement* filter = new TiXmlElement("Filter");
miscSettings->LinkEndChild(filter);
- addXmlElement(filter, "Active", inputCfg.cfg.filterIsActive);
- addXmlElement(filter, "Include", string((inputCfg.cfg.includeFilter).ToUTF8()));
- addXmlElement(filter, "Exclude", string((inputCfg.cfg.excludeFilter).ToUTF8()));
+ addXmlElement(filter, "Active", mainCfg.filterIsActive);
+ addXmlElement(filter, "Include", string((mainCfg.includeFilter).ToUTF8()));
+ addXmlElement(filter, "Exclude", string((mainCfg.excludeFilter).ToUTF8()));
//other
- addXmlElement(miscSettings, "Recycler", inputCfg.cfg.useRecycleBin);
- addXmlElement(miscSettings, "Continue", inputCfg.cfg.continueOnError);
+ addXmlElement(miscSettings, "Recycler", mainCfg.useRecycleBin);
+ addXmlElement(miscSettings, "Continue", mainCfg.continueOnError);
//###########################################################
return true;
}
-bool XmlOutput::writeXmlGuiConfig(const XmlGuiConfig& inputCfg)
+bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& inputCfg)
{
+ //write main config
+ if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs))
+ return false;
+
+ //write GUI specific config
TiXmlElement* root = doc.RootElement();
if (!root) return false;
@@ -444,41 +643,81 @@ bool XmlOutput::writeXmlGuiConfig(const XmlGuiConfig& inputCfg)
addXmlElement(mainWindow, "HideFiltered", inputCfg.hideFilteredElements);
- //window size
- addXmlElement(mainWindow, "Width", inputCfg.widthNotMaximized);
- addXmlElement(mainWindow, "Height", inputCfg.heightNotMaximized);
+ return true;
+}
- //window position
- addXmlElement(mainWindow, "PosX", inputCfg.posXNotMaximized);
- addXmlElement(mainWindow, "PosY", inputCfg.posYNotMaximized);
- addXmlElement(mainWindow, "Maximized", inputCfg.isMaximized);
- //write column sizes
- TiXmlElement* leftColumn = new TiXmlElement("LeftColumns");
- mainWindow->LinkEndChild(leftColumn);
+bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& inputCfg)
+{
+ //write main config
+ if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs))
+ return false;
- for (unsigned int i = 0; i < inputCfg.columnWidthLeft.size(); ++i)
- addXmlElement(leftColumn, "Width", inputCfg.columnWidthLeft[i]);
+ //write GUI specific config
+ TiXmlElement* root = doc.RootElement();
+ if (!root) return false;
- TiXmlElement* rightColumn = new TiXmlElement("RightColumns");
- mainWindow->LinkEndChild(rightColumn);
+ TiXmlElement* batchConfig = new TiXmlElement("BatchConfig");
+ root->LinkEndChild(batchConfig);
- for (unsigned int i = 0; i < inputCfg.columnWidthRight.size(); ++i)
- addXmlElement(rightColumn, "Width", inputCfg.columnWidthRight[i]);
+ addXmlElement(batchConfig, "Silent", inputCfg.silent);
return true;
}
-bool XmlOutput::writeXmlBatchConfig(const XmlBatchConfig& inputCfg)
+bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg)
{
TiXmlElement* root = doc.RootElement();
if (!root) return false;
- TiXmlElement* batchConfig = new TiXmlElement("BatchConfig");
- root->LinkEndChild(batchConfig);
+ //###################################################################
+ //write global settings
+ TiXmlElement* global = new TiXmlElement("Global");
+ root->LinkEndChild(global);
- addXmlElement(batchConfig, "Silent", inputCfg.silent);
+ //program language
+ addXmlElement(global, "Language", inputCfg.global.programLanguage);
+
+ //###################################################################
+ //write gui settings
+ TiXmlElement* guiLayout = new TiXmlElement("Gui");
+ root->LinkEndChild(guiLayout);
+
+ TiXmlElement* windows = new TiXmlElement("Windows");
+ guiLayout->LinkEndChild(windows);
+
+ TiXmlElement* mainWindow = new TiXmlElement("Main");
+ windows->LinkEndChild(mainWindow);
+
+ //window size
+ addXmlElement(mainWindow, "Width", inputCfg.gui.widthNotMaximized);
+ addXmlElement(mainWindow, "Height", inputCfg.gui.heightNotMaximized);
+
+ //window position
+ addXmlElement(mainWindow, "PosX", inputCfg.gui.posXNotMaximized);
+ addXmlElement(mainWindow, "PosY", inputCfg.gui.posYNotMaximized);
+ addXmlElement(mainWindow, "Maximized", inputCfg.gui.isMaximized);
+
+ //write column sizes
+ TiXmlElement* leftColumn = new TiXmlElement("LeftColumns");
+ mainWindow->LinkEndChild(leftColumn);
+
+ for (unsigned int i = 0; i < inputCfg.gui.columnWidthLeft.size(); ++i)
+ addXmlElement(leftColumn, "Width", inputCfg.gui.columnWidthLeft[i]);
+
+ TiXmlElement* rightColumn = new TiXmlElement("RightColumns");
+ mainWindow->LinkEndChild(rightColumn);
+
+ for (unsigned int i = 0; i < inputCfg.gui.columnWidthRight.size(); ++i)
+ addXmlElement(rightColumn, "Width", inputCfg.gui.columnWidthRight[i]);
+
+
+ //###################################################################
+ //write batch settings
+
+ TiXmlElement* batch = new TiXmlElement("Batch");
+ root->LinkEndChild(batch);
return true;
}
diff --git a/library/processXml.h b/library/processXml.h
index d30cf49f..abf5bfc6 100644
--- a/library/processXml.h
+++ b/library/processXml.h
@@ -3,6 +3,8 @@
#include "../FreeFileSync.h"
#include "tinyxml/tinyxml.h"
+#include <wx/intl.h>
+
namespace xmlAccess
{
@@ -10,34 +12,21 @@ namespace xmlAccess
{
XML_GUI_CONFIG,
XML_BATCH_CONFIG,
+ XML_GLOBAL_SETTINGS,
XML_OTHER
};
-
- struct XmlMainConfig
- {
- MainConfiguration cfg;
- vector<FolderPair> directoryPairs;
- };
+ XmlType getXmlType(const wxString& filename);
struct XmlGuiConfig
{
- XmlGuiConfig() :
- hideFilteredElements(false), //initialize values
- widthNotMaximized(-1),
- heightNotMaximized(-1),
- posXNotMaximized(-1),
- posYNotMaximized(-1),
- isMaximized(false) {}
+ XmlGuiConfig() : hideFilteredElements(false) {} //initialize values
+
+ MainConfiguration mainCfg;
+ vector<FolderPair> directoryPairs;
+
bool hideFilteredElements;
- int widthNotMaximized;
- int heightNotMaximized;
- int posXNotMaximized;
- int posYNotMaximized;
- bool isMaximized;
- vector<int> columnWidthLeft;
- vector<int> columnWidthRight;
};
@@ -45,68 +34,50 @@ namespace xmlAccess
{
XmlBatchConfig() : silent(false) {}
+ MainConfiguration mainCfg;
+ vector<FolderPair> directoryPairs;
+
bool silent;
};
- XmlType getXmlType(const wxString& filename);
-
- class XmlInput
+ struct XmlGlobalSettings
{
- public:
- XmlInput(const wxString& fileName, const XmlType type);
- ~XmlInput() {}
+ struct _Global
+ {
+ _Global() : programLanguage(wxLocale::GetSystemLanguage()) {}
+ int programLanguage;
+ } global;
- bool loadedSuccessfully()
+ struct _Gui
{
- return loadSuccess;
- }
-
- //read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully
- bool readXmlMainConfig(XmlMainConfig& outputCfg);
- //read additional gui settings, all values retrieved are optional, so check for initial values! (== -1)
- bool readXmlGuiConfig(XmlGuiConfig& outputCfg);
- //read additional batch settings, all values retrieved are optional
- bool readXmlBatchConfig(XmlBatchConfig& outputCfg);
-
- private:
-//read
- bool readXmlElementValue(string& output, const TiXmlElement* parent, const string& name);
- bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& name);
- bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name);
- bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const string& name);
- bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name);
-
- TiXmlDocument doc;
- bool loadSuccess;
+ _Gui() :
+ widthNotMaximized(wxDefaultCoord),
+ heightNotMaximized(wxDefaultCoord),
+ posXNotMaximized(wxDefaultCoord),
+ posYNotMaximized(wxDefaultCoord),
+ isMaximized(false) {}
+
+ int widthNotMaximized;
+ int heightNotMaximized;
+ int posXNotMaximized;
+ int posYNotMaximized;
+ bool isMaximized;
+ vector<int> columnWidthLeft;
+ vector<int> columnWidthRight;
+ } gui;
+
+ //struct _Batch
};
- class XmlOutput
- {
- public:
- XmlOutput(const wxString& fileName, const XmlType type);
- ~XmlOutput() {}
-
- bool writeToFile();
-
- //write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully
- bool writeXmlMainConfig(const XmlMainConfig& inputCfg);
- //write additional gui settings
- bool writeXmlGuiConfig(const XmlGuiConfig& inputCfg);
- //write additional batch settings
- bool writeXmlBatchConfig(const XmlBatchConfig& inputCfg);
-
- private:
-//write
- void addXmlElement(TiXmlElement* parent, const string& name, const string& value);
- void addXmlElement(TiXmlElement* parent, const string& name, const int value);
- void addXmlElement(TiXmlElement* parent, const string& name, const SyncDirection value);
- void addXmlElement(TiXmlElement* parent, const string& name, const bool value);
-
- TiXmlDocument doc;
- const wxString& m_fileName;
- };
+ XmlGuiConfig readGuiConfig(const wxString& filename);
+ XmlBatchConfig readBatchConfig(const wxString& filename);
+ XmlGlobalSettings readGlobalSettings(); //used for both GUI and batch mode, independent from configuration instance
+
+ void writeGuiConfig(const wxString& filename, const XmlGuiConfig& inputCfg);
+ void writeBatchConfig(const wxString& filename, const XmlBatchConfig& inputCfg);
+ void writeGlobalSettings(const XmlGlobalSettings& inputCfg);
}
diff --git a/library/resources.cpp b/library/resources.cpp
index 9fce4501..2156fd50 100644
--- a/library/resources.cpp
+++ b/library/resources.cpp
@@ -40,18 +40,24 @@ GlobalResources::GlobalResources()
bitmapResource[wxT("sync disabled.png")] = (bitmapSyncDisabled = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("swap.png")] = (bitmapSwap = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("help.png")] = (bitmapHelp = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("leftOnly.png")] = (bitmapLeftOnly = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("leftNewer.png")] = (bitmapLeftNewer = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("rightNewer.png")] = (bitmapRightNewer = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("leftOnlyAct.png")] = (bitmapLeftOnlyAct = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("leftOnlyDeact.png")] = (bitmapLeftOnlyDeact = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("leftNewer.png")] = (bitmapLeftNewer = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("leftNewerAct.png")] = (bitmapLeftNewerAct = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("leftNewerDeact.png")] = (bitmapLeftNewerDeact = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("rightNewer.png")] = (bitmapRightNewer = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("rightNewerAct.png")] = (bitmapRightNewerAct = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("rightNewerDeact.png")] = (bitmapRightNewerDeact = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap));
- bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("include.png")] = (bitmapInclude = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("exclude.png")] = (bitmapExclude = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("filter active.png")] = (bitmapFilterOn = new wxBitmap(wxNullBitmap));
@@ -77,6 +83,7 @@ GlobalResources::GlobalResources()
bitmapResource[wxT("remove pair.png")] = (bitmapRemoveFolderPair = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("remove pair disabl.png")] = (bitmapRemoveFolderPairD = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("link.png")] = (bitmapLink = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("background.png")] = (bitmapBackground = new wxBitmap(wxNullBitmap));
//init all the other resource files
animationMoney = new wxAnimation(wxNullAnimation);
@@ -103,7 +110,7 @@ void GlobalResources::load()
if (input.IsOk()) //if not... we don't want to react too harsh here
{
//activate support for .png files
- wxImage::AddHandler(new wxPNGHandler);
+ wxImage::AddHandler(new wxPNGHandler); //ownership passed
wxZipInputStream resourceFile(input);
diff --git a/library/resources.h b/library/resources.h
index 711c6038..c91b5cb7 100644
--- a/library/resources.h
+++ b/library/resources.h
@@ -41,18 +41,24 @@ public:
wxBitmap* bitmapSyncDisabled;
wxBitmap* bitmapSwap;
wxBitmap* bitmapHelp;
+ wxBitmap* bitmapEqual;
+ wxBitmap* bitmapEqualAct;
+ wxBitmap* bitmapEqualDeact;
wxBitmap* bitmapLeftOnly;
- wxBitmap* bitmapLeftNewer;
- wxBitmap* bitmapDifferent;
- wxBitmap* bitmapRightNewer;
- wxBitmap* bitmapRightOnly;
+ wxBitmap* bitmapLeftOnlyAct;
wxBitmap* bitmapLeftOnlyDeact;
+ wxBitmap* bitmapLeftNewer;
+ wxBitmap* bitmapLeftNewerAct;
wxBitmap* bitmapLeftNewerDeact;
+ wxBitmap* bitmapDifferent;
+ wxBitmap* bitmapDifferentAct;
wxBitmap* bitmapDifferentDeact;
+ wxBitmap* bitmapRightNewer;
+ wxBitmap* bitmapRightNewerAct;
wxBitmap* bitmapRightNewerDeact;
+ wxBitmap* bitmapRightOnly;
+ wxBitmap* bitmapRightOnlyAct;
wxBitmap* bitmapRightOnlyDeact;
- wxBitmap* bitmapEqual;
- wxBitmap* bitmapEqualDeact;
wxBitmap* bitmapInclude;
wxBitmap* bitmapExclude;
wxBitmap* bitmapFilterOn;
@@ -78,6 +84,7 @@ public:
wxBitmap* bitmapRemoveFolderPair;
wxBitmap* bitmapRemoveFolderPairD;
wxBitmap* bitmapLink;
+ wxBitmap* bitmapBackground;
wxAnimation* animationMoney;
wxAnimation* animationSync;
diff --git a/library/sorting.h b/library/sorting.h
new file mode 100644
index 00000000..0faa1bfd
--- /dev/null
+++ b/library/sorting.h
@@ -0,0 +1,274 @@
+#ifndef SORTING_H_INCLUDED
+#define SORTING_H_INCLUDED
+
+#include "../FreeFileSync.h"
+#include "resources.h"
+
+
+enum SideToSort
+{
+ SORT_ON_LEFT,
+ SORT_ON_RIGHT,
+};
+
+
+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)
+{
+ if (side == SORT_ON_LEFT)
+ {
+ descrLineA = &a.fileDescrLeft;
+ descrLineB = &b.fileDescrLeft;
+ }
+ else if (side == SORT_ON_RIGHT)
+ {
+ descrLineA = &a.fileDescrRight;
+ descrLineB = &b.fileDescrRight;
+ }
+ else assert(false);
+}
+
+
+inline
+wxChar formatChar(const wxChar& c)
+{
+ return c;
+ //return wxTolower(c); <- this is slow as hell! sorting slower by factor 10
+}
+
+
+inline
+int compareString(const wxChar* stringA, const wxChar* stringB, const int lengthA, const int lengthB)
+{
+ int i = 0;
+ if (lengthA == lengthB)
+ {
+ for (i = 0; i < lengthA; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthA ? 0 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+ else if (lengthA < lengthB)
+ {
+ for (i = 0; i < lengthA; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthA ? -1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+ else
+ {
+ for (i = 0; i < lengthB; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthB ? 1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //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
+ {
+ const wxChar* stringA = NULL;
+ const wxChar* stringB = NULL;
+ int lenghtA = 0;
+ int lenghtB = 0;
+
+ int pos = descrLineA->relativeName.Find(GlobalResources::fileNameSeparator, 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);
+ }
+
+ pos = descrLineB->relativeName.Find(GlobalResources::fileNameSeparator, 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);
+ }
+
+ int rv = compareString(stringA, stringB, lenghtA, lenghtB);
+ return sortAscending ? (rv == -1) : (rv != -1);
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //extract relative name and filename
+ const wxChar* relStringA = NULL;
+ const wxChar* fileStringA = NULL;
+ int relLenghtA = 0;
+ int fileLengthA = 0;
+ if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ relStringA = descrLineA->relativeName.c_str();
+ relLenghtA = descrLineA->relativeName.Len();
+ }
+ else if (descrLineA->objType == FileDescrLine::TYPE_FILE)
+ {
+ relLenghtA = descrLineA->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (relLenghtA == wxNOT_FOUND)
+ {
+ relLenghtA = 0;
+ fileStringA = descrLineA->relativeName.c_str();
+ fileLengthA = descrLineA->relativeName.Len();
+ }
+ else
+ {
+ relStringA = descrLineA->relativeName.c_str();
+ fileStringA = descrLineA->relativeName.c_str() + relLenghtA + 1;
+ fileLengthA = descrLineA->relativeName.Len() - (relLenghtA + 1);
+ }
+ }
+ else
+ return false; //empty rows should be on end of list
+
+
+ const wxChar* relStringB = NULL;
+ const wxChar* fileStringB = NULL;
+ int relLenghtB = 0;
+ int fileLengthB = 0;
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ relStringB = descrLineB->relativeName.c_str();
+ relLenghtB = descrLineB->relativeName.Len();
+ }
+ else if (descrLineB->objType == FileDescrLine::TYPE_FILE)
+ {
+ relLenghtB = descrLineB->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (relLenghtB == wxNOT_FOUND)
+ {
+ relLenghtB = 0;
+ fileStringB = descrLineB->relativeName.c_str();
+ fileLengthB = descrLineB->relativeName.Len();
+ }
+ else
+ {
+ relStringB = descrLineB->relativeName.c_str();
+ fileStringB = descrLineB->relativeName.c_str() + relLenghtB + 1;
+ fileLengthB = descrLineB->relativeName.Len() - (relLenghtB + 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);
+ if (rv != 0)
+ return sortAscending ? (rv == -1) : (rv != -1);
+ else //compare the filenames
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) //directories shall appear before files
+ return false;
+ else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+
+ rv = compareString(fileStringA, fileStringB, fileLengthA, fileLengthB);
+ return sortAscending ? (rv == -1) : (rv != -1);
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //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 //use unformatted filesizes and sort by size
+ return cmpLargeInt<sortAscending>(descrLineA->fileSize, descrLineB->fileSize);
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByDate(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ return cmpString<sortAscending>(descrLineA->lastWriteTime, descrLineB->lastWriteTime);
+}
+
+
+#endif // SORTING_H_INCLUDED
diff --git a/library/statusHandler.h b/library/statusHandler.h
new file mode 100644
index 00000000..ad4cb3a0
--- /dev/null
+++ b/library/statusHandler.h
@@ -0,0 +1,76 @@
+#ifndef STATUSHANDLER_H_INCLUDED
+#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
+
+bool updateUiIsAllowed(); //test if a specific amount of time is over
+void updateUiNow(); //do the updating
+
+
+//interfaces for status updates (can be implemented by UI or commandline)
+//overwrite virtual methods for respective functionality
+
+class ErrorHandler
+{
+public:
+ ErrorHandler() {}
+ virtual ~ErrorHandler() {}
+
+ enum Response
+ {
+ CONTINUE_NEXT = -1,
+ RETRY = -2
+ };
+ virtual Response reportError(const wxString& text) = 0;
+};
+
+
+class StatusHandler
+{
+public:
+ StatusHandler() :
+ abortionRequested(false) {}
+ virtual ~StatusHandler() {}
+
+ //identifiers of different processes
+ enum Process
+ {
+ PROCESS_NONE = 10,
+ PROCESS_SCANNING,
+ PROCESS_COMPARING_CONTENT,
+ PROCESS_SYNCHRONIZING
+ };
+
+ //these methods have to be implemented in the derived classes to handle error and status information
+ virtual void updateStatusText(const wxString& text) = 0;
+ virtual void initNewProcess(int objectsTotal, double dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
+ virtual void updateProcessedData(int objectsProcessed, double dataProcessed) = 0; //called periodically after data was processed
+ virtual ErrorHandler::Response reportError(const wxString& text) = 0;
+
+ //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
+ virtual void forceUiRefresh() = 0;
+ void requestUiRefresh(bool asyncProcessActive = false)
+ {
+ if (updateUiIsAllowed()) //test if specific time span between ui updates is over
+ forceUiRefresh();
+
+ if (abortionRequested && !asyncProcessActive)
+ abortThisProcess(); //abort can be triggered by requestAbortion()
+ }
+
+ void requestAbortion() //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
+ { //currently used by the UI status information screen, when button "Abort is pressed"
+ abortionRequested = true;
+ }
+
+protected:
+ virtual void abortThisProcess() = 0;
+
+ bool abortionRequested;
+};
+
+
+#endif // STATUSHANDLER_H_INCLUDED
diff --git a/library/wxWidgets.h b/library/wxWidgets.h
deleted file mode 100644
index a383a6f4..00000000
--- a/library/wxWidgets.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef WXWIDGETS_H_INCLUDED
-#define WXWIDGETS_H_INCLUDED
-
-// For compilers that support precompilation
-#include <wx/wxprec.h>
-
-#ifdef __BORLANDC__
-#pragma hdrstop
-#endif //__BORLANDC__
-
-#ifndef WX_PRECOMP
-#include <wx/wx.h>
-#endif
-
-#ifdef WX_PRECOMP
-// put here all your rarely-changing header files
-#endif // WX_PRECOMP
-
-#endif // WXWIDGETS_H_INCLUDED
diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp
index 47926383..3f845364 100644
--- a/ui/MainDialog.cpp
+++ b/ui/MainDialog.cpp
@@ -15,16 +15,18 @@
#include <wx/file.h>
#include "../library/customGrid.h"
#include <algorithm>
-#include "../library/processXml.h"
+#include "../library/sorting.h"
#include <wx/msgdlg.h>
using namespace globalFunctions;
using namespace xmlAccess;
+
int leadingPanel = 0;
-MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language) :
+MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings) :
GuiGenerated(frame),
+ globalSettings(settings),
programLanguage(language),
filteringInitialized(false),
filteringPending(false),
@@ -49,6 +51,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale
//initialize and load configuration
readConfigurationFromXml(cfgFileName, true);
+ readGlobalSettings();
leftOnlyFilesActive = true;
leftNewerFilesActive = true;
@@ -186,6 +189,9 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale
case wxLANGUAGE_JAPANESE:
m_menuItemJapanese->Check();
break;
+ case wxLANGUAGE_DUTCH:
+ m_menuItemDutch->Check();
+ break;
default:
m_menuItemEnglish->Check();
}
@@ -238,16 +244,62 @@ MainDialog::~MainDialog()
//save configuration
writeConfigurationToXml(FreeFileSync::FfsLastConfigFile); //don't trow exceptions in destructors
+ writeGlobalSettings();
if (restartOnExit) //this is needed so that restart happens AFTER configuration was written!
{ //create new dialog
- MainDialog* frame = new MainDialog(NULL, FreeFileSync::FfsLastConfigFile, programLanguage);
+ MainDialog* frame = new MainDialog(NULL, FreeFileSync::FfsLastConfigFile, programLanguage, globalSettings);
frame->SetIcon(*globalResource.programIcon); //set application icon
frame->Show();
}
}
+void MainDialog::readGlobalSettings()
+{
+ //apply window size and position at program startup ONLY
+ widthNotMaximized = globalSettings.gui.widthNotMaximized;
+ heightNotMaximized = globalSettings.gui.heightNotMaximized;
+ posXNotMaximized = globalSettings.gui.posXNotMaximized;
+ posYNotMaximized = globalSettings.gui.posYNotMaximized;
+
+ //apply window size and position
+ if ( widthNotMaximized != wxDefaultCoord &&
+ heightNotMaximized != wxDefaultCoord &&
+ posXNotMaximized != wxDefaultCoord &&
+ posYNotMaximized != wxDefaultCoord)
+ SetSize(posXNotMaximized, posYNotMaximized, widthNotMaximized, heightNotMaximized);
+
+ Maximize(globalSettings.gui.isMaximized);
+
+ //read column widths
+ for (int i = 0; i < m_grid1->GetNumberCols() && i < int(globalSettings.gui.columnWidthLeft.size()); ++i)
+ m_grid1->SetColSize(i, globalSettings.gui.columnWidthLeft[i]);
+
+ for (int i = 0; i < m_grid2->GetNumberCols() && i < int(globalSettings.gui.columnWidthRight.size()); ++i)
+ m_grid2->SetColSize(i, globalSettings.gui.columnWidthRight[i]);
+}
+
+
+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.columnWidthLeft.clear();
+ for (int i = 0; i < m_grid1->GetNumberCols(); ++i)
+ globalSettings.gui.columnWidthLeft.push_back(m_grid1->GetColSize(i));
+
+ globalSettings.gui.columnWidthRight.clear();
+ for (int i = 0; i < m_grid2->GetNumberCols(); ++i)
+ globalSettings.gui.columnWidthRight.push_back(m_grid2->GetColSize(i));
+}
+
+
void MainDialog::onGrid1access(wxEvent& event)
{
if (leadingPanel != 1)
@@ -307,7 +359,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View)
{
int gridSizeUI = gridRefUI.size();
- bool newSelection = false; //default: deselect range
+ bool newSelection = false; //default: deselect range
//leadingRow determines de-/selection of all other rows
int leadingRow = *rowsToFilterOnUI_View.begin();
@@ -315,7 +367,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View)
newSelection = !currentGridData[gridRefUI[leadingRow]].selectedForSynchronization;
if (hideFilteredElements)
- assert (!newSelection); //if hidefiltered is active, there should be no filtered elements on screen => current element was filtered out
+ assert(!newSelection); //if hidefiltered is active, there should be no filtered elements on screen => current element was filtered out
//get all lines that need to be filtered (e.g. if a folder is marked, then its subelements should be marked as well)
@@ -340,33 +392,12 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View)
m_grid1->ForceRefresh();
m_grid2->ForceRefresh();
m_grid3->ForceRefresh();
+ Update(); //show changes resulting from ForceRefresh()
if (hideFilteredElements)
{
- Update(); //show changes resulting from ForceRefresh()
-
- wxLongLong waitBegin = wxGetLocalTimeMillis();
-
- //determine rows that are currently filtered out on current UI view (and need to be removed)
- set<int> filteredOutRowsOnUI;
- for (GridView::iterator i = gridRefUI.begin(); i != gridRefUI.end(); ++i)
- {
- const FileCompareLine& gridLine = currentGridData[*i];
-
- if (!gridLine.selectedForSynchronization)
- filteredOutRowsOnUI.insert(i - gridRefUI.begin());
- }
-
- //some delay to show user the rows he has filtered out before they are removed
- unsigned long waitRemaining = max(400 - (wxGetLocalTimeMillis() - waitBegin).GetLo(), unsigned(0));
- wxMilliSleep(waitRemaining); //400 ms delay before rows are removed from UI
-
- //delete rows, that are filtered out:
- removeRowsFromVector(gridRefUI, filteredOutRowsOnUI);
-
- //redraw grid necessary to update new dimensions
- writeGrid(currentGridData, true); //use UI buffer, just a re-dimensioning of grids
- updateStatusInformation(gridRefUI); //status information has to be recalculated!
+ wxMilliSleep(400); //some delay to show user the rows he has filtered out before they are removed
+ writeGrid(currentGridData); //redraw grid to remove excluded elements (keeping sort sequence)
}
}
@@ -379,6 +410,7 @@ void MainDialog::filterRangeTemp(const set<int>& rowsToFilterOnUI_View)
m_grid3->ClearSelection();
}
+
/*grid event choreography:
1. UI-Mouse-Down => OnGridSelectCell
2. UI-Mouse-Up => SelectRangeEvent (if at least two rows are marked)
@@ -572,18 +604,18 @@ set<int> MainDialog::getSelectedRows()
}
-class DeleteStatusUpdater : public StatusUpdater
+class DeleteErrorHandler : public ErrorHandler
{
public:
- DeleteStatusUpdater(bool& unsolvedErrorOccured) : continueOnError(false), unsolvedErrors(unsolvedErrorOccured) {}
- ~DeleteStatusUpdater() {}
+ DeleteErrorHandler(bool& unsolvedErrorOccured) : continueOnError(false), unsolvedErrors(unsolvedErrorOccured) {}
+ ~DeleteErrorHandler() {}
- int reportError(const wxString& text)
+ Response reportError(const wxString& text)
{
if (continueOnError)
{
unsolvedErrors = true;
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
}
wxString errorMessage = text + _("\n\nInformation: If you skip the error and continue or abort a re-compare will be necessary!");
@@ -595,12 +627,12 @@ public:
switch (rv)
{
- case ErrorDlg::continueButtonPressed:
+ case ErrorDlg::BUTTON_CONTINUE:
unsolvedErrors = true;
- return StatusUpdater::continueNext;
- case ErrorDlg::retryButtonPressed:
- return StatusUpdater::retry;
- case ErrorDlg::abortButtonPressed:
+ return ErrorHandler::CONTINUE_NEXT;
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+ case ErrorDlg::BUTTON_ABORT:
{
unsolvedErrors = true;
throw AbortThisProcess();
@@ -609,14 +641,9 @@ public:
assert (false);
}
- return StatusUpdater::continueNext; //dummy return value
+ return ErrorHandler::CONTINUE_NEXT; //dummy return value
}
- void updateStatusText(const wxString& text) {}
- void initNewProcess(int objectsTotal, double dataTotal, int processID) {}
- void updateProcessedData(int objectsProcessed, double dataProcessed) {}
- void forceUiRefresh() {}
private:
- void abortThisProcess() {}
bool continueOnError;
bool& unsolvedErrors;
@@ -644,11 +671,11 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI)
{
const FileCompareLine& currentCmpLine = currentGridData[*i];
- if (currentCmpLine.fileDescrLeft.objType != TYPE_NOTHING)
- filesToDelete+= currentCmpLine.fileDescrLeft.filename + wxT("\n");
+ if (currentCmpLine.fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING)
+ filesToDelete+= currentCmpLine.fileDescrLeft.fullName + wxT("\n");
- if (currentCmpLine.fileDescrRight.objType != TYPE_NOTHING)
- filesToDelete+= currentCmpLine.fileDescrRight.filename + wxT("\n");
+ if (currentCmpLine.fileDescrRight.objType != FileDescrLine::TYPE_NOTHING)
+ filesToDelete+= currentCmpLine.fileDescrRight.fullName + wxT("\n");
filesToDelete+= wxT("\n");
}
@@ -657,38 +684,35 @@ void MainDialog::deleteFilesOnGrid(const set<int>& rowsToDeleteOnUI)
switch (confirmDeletion->ShowModal())
{
- case DeleteDialog::okayButtonPressed:
+ case DeleteDialog::BUTTON_OKAY:
{
bool unsolvedErrorOccured = false; //if an error is skipped a re-compare will be necessary!
try
- { //class errors when deleting files/folders
- DeleteStatusUpdater deleteStatusUpdater(unsolvedErrorOccured);
+ { //handle errors when deleting files/folders
+ DeleteErrorHandler errorHandler(unsolvedErrorOccured);
- FreeFileSync::deleteOnGridAndHD(currentGridData, rowsToDeleteOnGrid, &deleteStatusUpdater, cfg.useRecycleBin);
+ FreeFileSync::deleteOnGridAndHD(currentGridData, rowsToDeleteOnGrid, &errorHandler, cfg.useRecycleBin);
}
catch (AbortThisProcess& theException)
{}
-
//disable the sync button if errors occured during deletion
if (unsolvedErrorOccured)
enableSynchronization(false);
-
//redraw grid neccessary to update new dimensions and for UI-Backend data linkage
- writeGrid(currentGridData); //do NOT use UI buffer here
+ writeGrid(currentGridData);
- m_grid1->ClearSelection(); //clear selection on grid
- m_grid2->ClearSelection(); //clear selection on grid
- m_grid3->ClearSelection(); //clear selection on grid
+ m_grid1->ClearSelection();
+ m_grid2->ClearSelection();
+ m_grid3->ClearSelection();
}
break;
- case DeleteDialog::cancelButtonPressed:
+ case DeleteDialog::BUTTON_CANCEL:
default:
break;
-
}
}
}
@@ -703,10 +727,9 @@ void MainDialog::openWithFileBrowser(int rowNumber, int gridNr)
if (0 <= rowNumber && rowNumber < int(gridRefUI.size()))
{
- wxString filename = currentGridData[gridRefUI[rowNumber]].fileDescrLeft.filename;
-
- if (!filename.IsEmpty())
- command = wxString(wxT("explorer /select,")) + filename;
+ const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrLeft;
+ if (fileDescr.objType != FileDescrLine::TYPE_NOTHING)
+ command = wxString(wxT("explorer /select,")) + fileDescr.fullName;
}
wxExecute(command);
}
@@ -716,10 +739,9 @@ void MainDialog::openWithFileBrowser(int rowNumber, int gridNr)
if (0 <= rowNumber && rowNumber < int(gridRefUI.size()))
{
- wxString filename = currentGridData[gridRefUI[rowNumber]].fileDescrRight.filename;
-
- if (!filename.IsEmpty())
- command = wxString(wxT("explorer /select,")) + filename;
+ const FileDescrLine& fileDescr = currentGridData[gridRefUI[rowNumber]].fileDescrRight;
+ if (fileDescr.objType != FileDescrLine::TYPE_NOTHING)
+ command = wxString(wxT("explorer /select,")) + fileDescr.fullName;
}
wxExecute(command);
}
@@ -816,57 +838,13 @@ void MainDialog::onGrid3ButtonEvent(wxKeyEvent& event)
}
-inline
-wxString getFilename(const FileDescrLine* fileDescr)
-{
- if (!fileDescr || fileDescr->objType != TYPE_FILE)
- return wxEmptyString;
- else
- return fileDescr->relFilename.AfterLast(GlobalResources::fileNameSeparator);
-}
-
-
-inline
-wxString getFileExtension(const FileDescrLine* fileDescr)
-{
- if (!fileDescr || fileDescr->objType != TYPE_FILE)
- return wxEmptyString;
- else
- {
- wxString filename = getFilename(fileDescr);
-
- if (filename.Find(wxChar('.')) != wxNOT_FOUND) //be careful: AfterLast will return the whole string if '.' is not found!
- return filename.AfterLast(wxChar('.'));
- else
- return wxEmptyString;
- }
-}
-
-
-inline
-wxString getDirname(const FileDescrLine* fileDescr)
-{
- if (!fileDescr || fileDescr->objType != TYPE_DIRECTORY)
- return wxEmptyString;
- else
- return fileDescr->filename.AfterLast(GlobalResources::fileNameSeparator);
-}
-
-
-inline
-wxString getRelativeName(const FileDescrLine* fileDescr)
-{
- if (!fileDescr || fileDescr->objType == TYPE_NOTHING)
- return wxEmptyString;
- else
- return fileDescr->relFilename;
-}
-
-
void MainDialog::OnOpenContextMenu(wxGridEvent& event)
{
set<int> selection = getSelectedRows();
+ exFilterCandidateExtension.Clear();
+ exFilterCandidateObj.clear();
+
//#######################################################
//re-create context menu
delete contextMenu;
@@ -875,31 +853,49 @@ void MainDialog::OnOpenContextMenu(wxGridEvent& event)
//dynamic filter determination
if (selection.size() > 0)
{
- const FileCompareLine& cmpLine = currentGridData[gridRefUI[*selection.begin()]];
+ const FileCompareLine& firstLine = currentGridData[gridRefUI[*selection.begin()]];
- if (cmpLine.selectedForSynchronization)
+ if (firstLine.selectedForSynchronization)
contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily"));
else
contextMenu->Append(CONTEXT_FILTER_TEMP, _("Include temporarily"));
-
- const FileDescrLine* fileDescr = NULL;
+ //get list of relative file/dir-names into vectors
+ FilterObject newFilterEntry;
if (leadingPanel == 1)
- fileDescr = &cmpLine.fileDescrLeft;
+ for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i)
+ {
+ const FileCompareLine& line = currentGridData[gridRefUI[*i]];
+ newFilterEntry.relativeName = line.fileDescrLeft.relativeName;
+ newFilterEntry.type = line.fileDescrLeft.objType;
+ if (!newFilterEntry.relativeName.IsEmpty())
+ exFilterCandidateObj.push_back(newFilterEntry);
+ }
else if (leadingPanel == 2)
- fileDescr = &cmpLine.fileDescrRight;
+ for (set<int>::iterator i = selection.begin(); i != selection.end(); ++i)
+ {
+ const FileCompareLine& line = currentGridData[gridRefUI[*i]];
+ newFilterEntry.relativeName = line.fileDescrRight.relativeName;
+ newFilterEntry.type = line.fileDescrRight.objType;
+ if (!newFilterEntry.relativeName.IsEmpty())
+ exFilterCandidateObj.push_back(newFilterEntry);
+ }
- exFilterCandidateExtension = getFileExtension(fileDescr); //avoid re-determination in onContextMenuSelection()
- if (!exFilterCandidateExtension.IsEmpty())
- contextMenu->Append(CONTEXT_EXCLUDE_EXT, wxString(_("Add to exclude filter: ")) + wxT("*.") + exFilterCandidateExtension);
- exFilterCandidateFilename = getFilename(fileDescr);
- if (!exFilterCandidateFilename.IsEmpty())
- contextMenu->Append(CONTEXT_EXCLUDE_FILE, wxString(_("Add to exclude filter: ")) + exFilterCandidateFilename);
+ if (exFilterCandidateObj.size() > 0 && exFilterCandidateObj[0].type == FileDescrLine::TYPE_FILE)
+ {
+ const wxString filename = exFilterCandidateObj[0].relativeName.AfterLast(GlobalResources::fileNameSeparator);
+ 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);
+ }
+ }
- exFilterCandidateDirname = getDirname(fileDescr);
- if (!exFilterCandidateDirname.IsEmpty())
- contextMenu->Append(CONTEXT_EXCLUDE_DIR, wxString(_("Add to exclude filter: ")) + exFilterCandidateDirname);
+ if (exFilterCandidateObj.size() == 1)
+ contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + exFilterCandidateObj[0].relativeName);
+ else if (exFilterCandidateObj.size() > 1)
+ contextMenu->Append(CONTEXT_EXCLUDE_OBJ, wxString(_("Add to exclude filter: ")) + _("<multiple selection>"));
}
else
contextMenu->Append(CONTEXT_FILTER_TEMP, _("Exclude temporarily")); //this element should always be visible
@@ -967,31 +963,26 @@ void MainDialog::onContextMenuSelection(wxCommandEvent& event)
writeGrid(currentGridData);
}
}
- else if (eventId == CONTEXT_EXCLUDE_FILE)
- {
- if (!exFilterCandidateFilename.IsEmpty())
- {
- if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n")))
- cfg.excludeFilter+= wxT("\n");
-
- cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateFilename;
-
- cfg.filterIsActive = true;
- updateFilterButton(m_bpButtonFilter, cfg.filterIsActive);
-
- FreeFileSync::filterCurrentGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter);
- writeGrid(currentGridData);
- }
- }
- else if (eventId == CONTEXT_EXCLUDE_DIR)
+ else if (eventId == CONTEXT_EXCLUDE_OBJ)
{
- if (!exFilterCandidateDirname.IsEmpty())
+ if (exFilterCandidateObj.size() > 0) //check needed to determine if filtering is needed
{
- if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n")))
- cfg.excludeFilter+= wxT("\n");
+ for (vector<FilterObject>::const_iterator i = exFilterCandidateObj.begin(); i != exFilterCandidateObj.end(); ++i)
+ {
+ if (!cfg.excludeFilter.IsEmpty() && !cfg.excludeFilter.EndsWith(wxT("\n")))
+ cfg.excludeFilter+= wxT("\n");
- cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateDirname + wxT("\n");
- cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + exFilterCandidateDirname + GlobalResources::fileNameSeparator + wxT("*");
+ if (i->type == FileDescrLine::TYPE_FILE)
+ {
+ cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName;
+ }
+ else if (i->type == FileDescrLine::TYPE_DIRECTORY)
+ {
+ cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName + wxT("\n");
+ cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::fileNameSeparator + i->relativeName + GlobalResources::fileNameSeparator + wxT("*");
+ }
+ else assert(false);
+ }
cfg.filterIsActive = true;
updateFilterButton(m_bpButtonFilter, cfg.filterIsActive);
@@ -1358,161 +1349,87 @@ void MainDialog::OnQuit(wxCommandEvent &event)
}
-void MainDialog::loadDefaultConfiguration()
-{
- //default values
- cfg.syncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT;
- cfg.syncConfiguration.exRightSideOnly = SYNC_DIR_RIGHT;
- cfg.syncConfiguration.leftNewer = SYNC_DIR_RIGHT;
- cfg.syncConfiguration.rightNewer = SYNC_DIR_RIGHT;
- cfg.syncConfiguration.different = SYNC_DIR_RIGHT;
-
- cfg.compareVar = CMP_BY_TIME_SIZE; //compare algorithm
- updateCompareButtons();
-
- cfg.includeFilter = wxT("*"); //include all files/folders
- cfg.excludeFilter = wxEmptyString; //exclude nothing
-
- //set status of filter button
- cfg.filterIsActive = false; //do not filter by default
- updateFilterButton(m_bpButtonFilter, cfg.filterIsActive);
-
- cfg.useRecycleBin = FreeFileSync::recycleBinExists(); //enable if OS supports it; else user will have to activate first and then get the error message
- cfg.continueOnError = false;
-
- //set status of "hide filtered items" checkbox
- hideFilteredElements = false; //show filtered items
- m_checkBoxHideFilt->SetValue(hideFilteredElements);
-
- widthNotMaximized = wxDefaultCoord;
- heightNotMaximized = wxDefaultCoord;
- posXNotMaximized = wxDefaultCoord;
- posYNotMaximized = wxDefaultCoord;
-}
-
-
bool MainDialog::readConfigurationFromXml(const wxString& filename, bool programStartup)
{
//load XML
- XmlInput inputFile(filename, XML_GUI_CONFIG);
-
- if (!inputFile.loadedSuccessfully())
- { //handle error: file load
- if (programStartup)
- loadDefaultConfiguration();
- else
- wxMessageBox(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
- return false;
+ XmlGuiConfig guiCfg; //structure to receive gui settings, already defaulted!!
+ try
+ {
+ guiCfg = xmlAccess::readGuiConfig(filename);
}
-
- XmlMainConfig mainCfg; //structure to receive main settings
- XmlGuiConfig guiCfg; //structure to receive gui settings
- if ( inputFile.readXmlMainConfig(mainCfg) && //read main configuration settings
- inputFile.readXmlGuiConfig(guiCfg)) //read GUI layout configuration
+ catch (const FileError& error)
{
- //load main configuration into instance
- cfg = mainCfg.cfg;
+ if (programStartup && filename == FreeFileSync::FfsLastConfigFile && !wxFileExists(filename)) //do not show error in this case
+ ;
+ else if (!programStartup)
+ {
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
+ return false;
+ }
+ else //program startup: show error message and load defaults
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
+ }
- //update visible config on main window
- updateCompareButtons();
- updateFilterButton(m_bpButtonFilter, cfg.filterIsActive);
+ //load main configuration into instance
+ cfg = guiCfg.mainCfg;
- //read folder pairs, but first: clear existing pairs:
- removeFolderPair(true);
+ //update visible config on main window
+ updateCompareButtons();
+ updateFilterButton(m_bpButtonFilter, cfg.filterIsActive);
- //set main folder pair
- if (mainCfg.directoryPairs.size() > 0)
- {
- vector<FolderPair>::const_iterator i = mainCfg.directoryPairs.begin();
+ //read folder pairs, but first: clear existing pairs:
+ removeFolderPair(true);
- m_directoryLeft->SetValue(i->leftDirectory);
- wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(i->leftDirectory);
- if (wxDirExists(leftDirFormatted))
- m_dirPicker1->SetPath(leftDirFormatted);
+ //set main folder pair
+ if (guiCfg.directoryPairs.size() > 0)
+ {
+ vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin();
- m_directoryRight->SetValue(i->rightDirectory);
- wxString rightDirFormatted = FreeFileSync::getFormattedDirectoryName(i->rightDirectory);
- if (wxDirExists(rightDirFormatted))
- m_dirPicker2->SetPath(rightDirFormatted);
+ m_directoryLeft->SetValue(i->leftDirectory);
+ wxString leftDirFormatted = FreeFileSync::getFormattedDirectoryName(i->leftDirectory);
+ if (wxDirExists(leftDirFormatted))
+ m_dirPicker1->SetPath(leftDirFormatted);
- //set additional pairs
- for (vector<FolderPair>::const_iterator i = mainCfg.directoryPairs.begin() + 1; i != mainCfg.directoryPairs.end(); ++i)
- addFolderPair(i->leftDirectory, i->rightDirectory);
- }
+ m_directoryRight->SetValue(i->rightDirectory);
+ wxString rightDirFormatted = FreeFileSync::getFormattedDirectoryName(i->rightDirectory);
+ if (wxDirExists(rightDirFormatted))
+ m_dirPicker2->SetPath(rightDirFormatted);
- //read GUI layout (optional!)
- hideFilteredElements = guiCfg.hideFilteredElements;
- m_checkBoxHideFilt->SetValue(hideFilteredElements);
+ //set additional pairs
+ for (vector<FolderPair>::const_iterator i = guiCfg.directoryPairs.begin() + 1; i != guiCfg.directoryPairs.end(); ++i)
+ addFolderPair(i->leftDirectory, i->rightDirectory);
+ }
- //apply window size and position at program startup ONLY
- if (programStartup)
- {
- if ( guiCfg.widthNotMaximized != -1 &&
- guiCfg.heightNotMaximized != -1 &&
- guiCfg.posXNotMaximized != -1 &&
- guiCfg.posYNotMaximized != -1)
- {
- widthNotMaximized = guiCfg.widthNotMaximized;
- heightNotMaximized = guiCfg.heightNotMaximized;
- posXNotMaximized = guiCfg.posXNotMaximized;
- posYNotMaximized = guiCfg.posYNotMaximized;
-
- //apply window size and position
- SetSize(posXNotMaximized, posYNotMaximized, widthNotMaximized, heightNotMaximized);
- Maximize(guiCfg.isMaximized);
- }
- //read column widths
- for (int i = 0; i < m_grid1->GetNumberCols() && i < int(guiCfg.columnWidthLeft.size()); ++i)
- m_grid1->SetColSize(i, guiCfg.columnWidthLeft[i]);
+ //read GUI layout (optional!)
+ hideFilteredElements = guiCfg.hideFilteredElements;
+ m_checkBoxHideFilt->SetValue(hideFilteredElements);
- for (int i = 0; i < m_grid2->GetNumberCols() && i < int(guiCfg.columnWidthRight.size()); ++i)
- m_grid2->SetColSize(i, guiCfg.columnWidthRight[i]);
- }
- //###########################################################
- addCfgFileToHistory(filename); //put filename on list of last used config files
- return true;
- }
- else
- { //handle error: parsing
- wxMessageBox(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
- if (programStartup)
- loadDefaultConfiguration();
- return false;
- }
+ //###########################################################
+ addCfgFileToHistory(filename); //put filename on list of last used config files
+ return true;
}
bool MainDialog::writeConfigurationToXml(const wxString& filename)
{
- XmlOutput outputFile(filename, XML_GUI_CONFIG);
+ XmlGuiConfig guiCfg;
//load structure with basic settings "mainCfg"
- XmlMainConfig mainCfg;
- mainCfg.cfg = cfg;
- GetFolderPairs(mainCfg.directoryPairs);
+ guiCfg.mainCfg = cfg;
+ GetFolderPairs(guiCfg.directoryPairs);
- //load structure with gui settings "guiCfg"
- XmlGuiConfig guiCfg;
+ //load structure with gui settings
guiCfg.hideFilteredElements = hideFilteredElements;
- guiCfg.widthNotMaximized = widthNotMaximized;
- guiCfg.heightNotMaximized = heightNotMaximized;
- guiCfg.posXNotMaximized = posXNotMaximized;
- guiCfg.posYNotMaximized = posYNotMaximized;
- guiCfg.isMaximized = IsMaximized();
-
- for (int i = 0; i < m_grid1->GetNumberCols(); ++i)
- guiCfg.columnWidthLeft.push_back(m_grid1->GetColSize(i));
- for (int i = 0; i < m_grid2->GetNumberCols(); ++i)
- guiCfg.columnWidthRight.push_back(m_grid2->GetColSize(i));
-
- //populate and write XML tree
- if ( !outputFile.writeXmlMainConfig(mainCfg) || //add basic configuration settings
- !outputFile.writeXmlGuiConfig(guiCfg) || //add GUI layout configuration settings
- !outputFile.writeToFile()) //save XML
+ //write config to XML
+ try
+ {
+ xmlAccess::writeGuiConfig(filename, guiCfg);
+ }
+ catch (const FileError& error)
{
- wxMessageBox(wxString(_("Could not write configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
return false;
}
@@ -1563,7 +1480,7 @@ void MainDialog::OnConfigureFilter(wxHyperlinkEvent &event)
wxString beforeImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter;
FilterDlg* filterDlg = new FilterDlg(this, cfg.includeFilter, cfg.excludeFilter);
- if (filterDlg->ShowModal() == FilterDlg::okayButtonPressed)
+ if (filterDlg->ShowModal() == FilterDlg::BUTTON_OKAY)
{
wxString afterImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter;
@@ -1640,34 +1557,70 @@ void MainDialog::OnEqualFiles(wxCommandEvent& event)
void MainDialog::updateViewFilterButtons()
{
if (leftOnlyFilesActive)
- m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnly);
+ {
+ m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnlyAct);
+ m_bpButtonLeftOnly->SetToolTip(_("Hide files that exist on left side only"));
+ }
else
+ {
m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnlyDeact);
+ m_bpButtonLeftOnly->SetToolTip(_("Show files that exist on left side only"));
+ }
if (leftNewerFilesActive)
- m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewer);
+ {
+ m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewerAct);
+ m_bpButtonLeftNewer->SetToolTip(_("Hide files that are newer on left"));
+ }
else
+ {
m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewerDeact);
+ m_bpButtonLeftNewer->SetToolTip(_("Show files that are newer on left"));
+ }
if (equalFilesActive)
- m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqual);
+ {
+ m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqualAct);
+ m_bpButtonEqual->SetToolTip(_("Hide files that are equal"));
+ }
else
+ {
m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqualDeact);
+ m_bpButtonEqual->SetToolTip(_("Show files that are equal"));
+ }
if (differentFilesActive)
- m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferent);
+ {
+ m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferentAct);
+ m_bpButtonDifferent->SetToolTip(_("Hide files that are different"));
+ }
else
+ {
m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferentDeact);
+ m_bpButtonDifferent->SetToolTip(_("Show files that are different"));
+ }
if (rightNewerFilesActive)
- m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewer);
+ {
+ m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerAct);
+ m_bpButtonRightNewer->SetToolTip(_("Hide files that are newer on right"));
+ }
else
+ {
m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerDeact);
+ m_bpButtonRightNewer->SetToolTip(_("Show files that are newer on right"));
+ }
if (rightOnlyFilesActive)
- m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnly);
+ {
+ m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyAct);
+ m_bpButtonRightOnly->SetToolTip(_("Hide files that exist on right side only"));
+ }
else
+ {
m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyDeact);
+ m_bpButtonRightOnly->SetToolTip(_("Show files that exist on right side only"));
+ }
}
@@ -1772,13 +1725,10 @@ void MainDialog::OnCompare(wxCommandEvent &event)
CompareStatusUpdater statusUpdater(this);
cmpStatusUpdaterTmp = &statusUpdater;
- //unsigned int startTime3 = GetTickCount();
- FreeFileSync::startCompareProcess(currentGridData,
- directoryPairsFormatted,
+ FreeFileSync::startCompareProcess(directoryPairsFormatted,
cfg.compareVar,
+ currentGridData,
&statusUpdater);
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3));
-
//filter currentGridData if option is set
if (cfg.filterIsActive)
@@ -1802,6 +1752,10 @@ void MainDialog::OnCompare(wxCommandEvent &event)
{ //once compare is finished enable the sync button
enableSynchronization(true);
m_bpButtonSync->SetFocus();
+
+ //hide sort direction indicator on GUI grids
+ m_grid1->setSortMarker(-1);
+ m_grid2->setSortMarker(-1);
}
wxEndBusyCursor();
@@ -1817,23 +1771,17 @@ void MainDialog::OnAbortCompare(wxCommandEvent& event)
}
-void MainDialog::writeGrid(const FileCompareResult& gridData, bool useUI_GridCache)
+void MainDialog::writeGrid(const FileCompareResult& gridData)
{
m_grid1->BeginBatch();
m_grid2->BeginBatch();
m_grid3->BeginBatch();
- if (!useUI_GridCache)
- {
- //unsigned int startTime = GetTickCount();
- mapGridDataToUI(gridRefUI, gridData); //update gridRefUI
- //wxMessageBox(wxString("Benchmark: ") + numberToWxString(unsigned(GetTickCount()) - startTime) + " ms");
-
- updateStatusInformation(gridRefUI); //write status information for gridRefUI
- }
+ mapGridDataToUI(gridRefUI, gridData); //update gridRefUI
+ updateStatusInformation(gridRefUI); //write status information for gridRefUI
- //all three grids retrieve their data directly from currentGridData!!!
- //the only thing left to do is notify the grids to update their sizes (nr of rows), since this has to be communicated via messages by the grids
+ //all three grids retrieve their data directly via gridRefUI!!!
+ //the only thing left to do is notify the grids to update their sizes (nr of rows), since this has to be communicated by the grids via messages
m_grid1->updateGridSizes();
m_grid2->updateGridSizes();
m_grid3->updateGridSizes();
@@ -1847,11 +1795,6 @@ void MainDialog::writeGrid(const FileCompareResult& gridData, bool useUI_GridCac
m_grid2->SetRowLabelSize(nrOfDigits * 8 + 4);
}
- //hide sort direction indicator on UI grids
- m_grid1->setSortMarker(-1);
- m_grid2->setSortMarker(-1);
-
-
m_grid1->EndBatch();
m_grid2->EndBatch();
m_grid3->EndBatch();
@@ -1884,17 +1827,13 @@ void MainDialog::OnSync(wxCommandEvent& event)
wxBeginBusyCursor();
clearStatusBar();
-
try
{
//class handling status updates and error messages
SyncStatusUpdater statusUpdater(this, cfg.continueOnError);
//start synchronization and return elements that were not sync'ed in currentGridData
-
- //unsigned int startTime3 = GetTickCount();
FreeFileSync::startSynchronizationProcess(currentGridData, cfg.syncConfiguration, &statusUpdater, cfg.useRecycleBin);
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3));
}
catch (AbortThisProcess& theException)
{ //do NOT disable the sync button: user might want to try to sync the REMAINING rows
@@ -1912,7 +1851,6 @@ void MainDialog::OnSync(wxCommandEvent& event)
enableSynchronization(false);
}
-
wxEndBusyCursor();
}
event.Skip();
@@ -1933,170 +1871,37 @@ void MainDialog::OnRightGridDoubleClick(wxGridEvent& event)
}
-//these three global variables are ONLY used for the sorting in the following methods
-unsigned int currentSortColumn = 0;
-bool sortAscending = true;
-FileCompareResult* currentGridDataPtr = 0;
-
-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);
-}
-
-
-inline
-bool cmpLargeInt(const wxULongLong& a, const wxULongLong& b)
-{
- if (sortAscending)
- return (a < b);
-
- return (a > b);
-}
-
-
-bool sortGridLeft(const GridViewLine a, const GridViewLine b)
-{
- const FileDescrLine& gridDataLineA = (*currentGridDataPtr)[a].fileDescrLeft;
- const FileDescrLine& gridDataLineB = (*currentGridDataPtr)[b].fileDescrLeft;
-
- wxString stringA;
- wxString stringB;
-
- switch (currentSortColumn)
- {
- case 0:
- //presort types: first files, then directories then empty rows
- if (gridDataLineA.objType == TYPE_NOTHING)
- return false; //empty rows always last
- else if (gridDataLineB.objType == TYPE_NOTHING)
- return true; //empty rows always last
- else if (gridDataLineA.objType == TYPE_DIRECTORY)
- return false;
- else if (gridDataLineB.objType == TYPE_DIRECTORY)
- return true;
- else
- return cmpString(gridDataLineA.relFilename.AfterLast(GlobalResources::fileNameSeparator),
- gridDataLineB.relFilename.AfterLast(GlobalResources::fileNameSeparator));
- case 1:
- if (gridDataLineA.objType == TYPE_DIRECTORY)
- stringA = gridDataLineA.relFilename;
- else
- stringA = gridDataLineA.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
-
- if (gridDataLineB.objType == TYPE_DIRECTORY)
- stringB = gridDataLineB.relFilename;
- else
- stringB = gridDataLineB.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
-
- return cmpString(stringA, stringB);
-
- case 2:
- //presort types: first files, then directories then empty rows
- if (gridDataLineA.objType == TYPE_NOTHING)
- return false; //empty rows always last
- else if (gridDataLineB.objType == TYPE_NOTHING)
- return true; //empty rows always last
- else if (gridDataLineA.objType == TYPE_DIRECTORY)
- return false;
- else if (gridDataLineB.objType == TYPE_DIRECTORY)
- return true;
- else //use unformatted filesizes and sort by size
- return cmpLargeInt(gridDataLineA.fileSize, gridDataLineB.fileSize);
-
- case 3:
- return cmpString(gridDataLineA.lastWriteTime, gridDataLineB.lastWriteTime);
-
- default:
- assert(false);
- return true; //dummy command
- }
-}
-
-
-bool sortGridRight(const GridViewLine a, const GridViewLine b)
-{
- const FileDescrLine& gridDataLineA = (*currentGridDataPtr)[a].fileDescrRight;
- const FileDescrLine& gridDataLineB = (*currentGridDataPtr)[b].fileDescrRight;
-
- wxString stringA;
- wxString stringB;
-
- switch (currentSortColumn)
- {
- case 0:
- //presort types: first files, then directories then empty rows
- if (gridDataLineA.objType == TYPE_NOTHING)
- return false; //empty rows always last
- else if (gridDataLineB.objType == TYPE_NOTHING)
- return true; //empty rows always last
- else if (gridDataLineA.objType == TYPE_DIRECTORY)
- return false;
- else if (gridDataLineB.objType == TYPE_DIRECTORY)
- return true;
- else
- return cmpString(gridDataLineA.relFilename.AfterLast(GlobalResources::fileNameSeparator),
- gridDataLineB.relFilename.AfterLast(GlobalResources::fileNameSeparator));
-
- case 1:
- if (gridDataLineA.objType == TYPE_DIRECTORY)
- stringA = gridDataLineA.relFilename;
- else
- stringA = gridDataLineA.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
-
- if (gridDataLineB.objType == TYPE_DIRECTORY)
- stringB = gridDataLineB.relFilename;
- else
- stringB = gridDataLineB.relFilename.BeforeLast(GlobalResources::fileNameSeparator);
-
- return cmpString(stringA, stringB);
-
- case 2:
- //presort types: first files, then directories then empty rows
- if (gridDataLineA.objType == TYPE_NOTHING)
- return false; //empty rows always last
- else if (gridDataLineB.objType == TYPE_NOTHING)
- return true; //empty rows always last
- else if (gridDataLineA.objType == TYPE_DIRECTORY)
- return false;
- else if (gridDataLineB.objType == TYPE_DIRECTORY)
- return true;
- else //use unformatted filesizes and sort by size
- return cmpLargeInt(gridDataLineA.fileSize, gridDataLineB.fileSize);
-
- case 3:
- return cmpString(gridDataLineA.lastWriteTime, gridDataLineB.lastWriteTime);
-
- default:
- assert(false);
- return true; //dummy command
- }
-}
-
-
void MainDialog::OnSortLeftGrid(wxGridEvent& event)
{
static bool columnSortAscending[4] = {true, true, false, true};
- currentSortColumn = event.GetCol();
- currentGridDataPtr = &currentGridData;
+ int currentSortColumn = event.GetCol();
if (0 <= currentSortColumn && currentSortColumn <= 3)
{
- sortAscending = columnSortAscending[currentSortColumn];
- columnSortAscending[currentSortColumn] = !columnSortAscending[currentSortColumn];
- sort(gridRefUI.begin(), gridRefUI.end(), sortGridLeft);
+ bool& sortAscending = columnSortAscending[currentSortColumn];
- m_grid1->ForceRefresh();
- m_grid2->ForceRefresh();
- m_grid3->ForceRefresh();
+ if (currentSortColumn == 0)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_LEFT>); //probably faster than qsort(), since gridRefUI is vector<int>
+ else sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_LEFT>);
+ }
+ else if (currentSortColumn == 1)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_LEFT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_LEFT>);
+ }
+ else if (currentSortColumn == 2)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_LEFT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_LEFT>);
+ }
+ else if (currentSortColumn == 3)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_LEFT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_LEFT>);
+ }
+
+ writeGrid(currentGridData); //needed to refresh gridRefUI references
//set sort direction indicator on UI
if (sortAscending)
@@ -2104,6 +1909,8 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event)
else
m_grid1->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown);
m_grid2->setSortMarker(-1);
+
+ sortAscending = !sortAscending;
}
event.Skip();
}
@@ -2113,17 +1920,33 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event)
{
static bool columnSortAscending[4] = {true, true, false, true};
- currentSortColumn = event.GetCol();
- currentGridDataPtr = &currentGridData;
+ int currentSortColumn = event.GetCol();
if (0 <= currentSortColumn && currentSortColumn <= 3)
{
- sortAscending = columnSortAscending[currentSortColumn];
- columnSortAscending[currentSortColumn] = !columnSortAscending[currentSortColumn];
- sort(gridRefUI.begin(), gridRefUI.end(), sortGridRight);
+ bool& sortAscending = columnSortAscending[currentSortColumn];
- m_grid1->ForceRefresh();
- m_grid2->ForceRefresh();
- m_grid3->ForceRefresh();
+ if (currentSortColumn == 0)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileName<true, SORT_ON_RIGHT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByFileName<false, SORT_ON_RIGHT>);
+ }
+ else if (currentSortColumn == 1)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<true, SORT_ON_RIGHT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByRelativeName<false, SORT_ON_RIGHT>);
+ }
+ else if (currentSortColumn == 2)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<true, SORT_ON_RIGHT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByFileSize<false, SORT_ON_RIGHT>);
+ }
+ else if (currentSortColumn == 3)
+ {
+ if (sortAscending) sort(currentGridData.begin(), currentGridData.end(), sortByDate<true, SORT_ON_RIGHT>);
+ else sort(currentGridData.begin(), currentGridData.end(), sortByDate<false, SORT_ON_RIGHT>);
+ }
+
+ writeGrid(currentGridData); //needed to refresh gridRefUI references
//set sort direction indicator on UI
m_grid1->setSortMarker(-1);
@@ -2131,6 +1954,8 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event)
m_grid2->setSortMarker(currentSortColumn, globalResource.bitmapSmallUp);
else
m_grid2->setSortMarker(currentSortColumn, globalResource.bitmapSmallDown);
+
+ sortAscending = !sortAscending;
}
event.Skip();
}
@@ -2180,26 +2005,26 @@ void MainDialog::updateStatusInformation(const GridView& visibleGrid)
const FileCompareLine& refLine = currentGridData[*i];
//calculate total number of bytes for each side
- if (refLine.fileDescrLeft.objType == TYPE_FILE)
+ if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE)
{
filesizeLeftView+= refLine.fileDescrLeft.fileSize;
++filesOnLeftView;
}
- else if (refLine.fileDescrLeft.objType == TYPE_DIRECTORY)
+ else if (refLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
++foldersOnLeftView;
- if (refLine.fileDescrRight.objType == TYPE_FILE)
+ if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE)
{
filesizeRightView+= refLine.fileDescrRight.fileSize;
++filesOnRightView;
}
- else if (refLine.fileDescrRight.objType == TYPE_DIRECTORY)
+ else if (refLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
++foldersOnRightView;
}
//#################################################
-// format numbers to text
+//format numbers to text:
-//show status information on "root" level. This cannot be accomplished in writeGrid since filesizes are already formatted for display there
+//show status information on "root" level.
if (foldersOnLeftView)
{
wxString folderCount = numberToWxString(foldersOnLeftView);
@@ -2292,6 +2117,10 @@ void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& file
unsigned int currentRow = 0;
for (FileCompareResult::const_iterator i = fileCmpResult.begin(); i != fileCmpResult.end(); ++i, ++currentRow)
{
+ //hide filtered row, if corresponding option is set
+ if (hideFilteredElements && !i->selectedForSynchronization)
+ continue;
+
//process UI filter settings
switch (i->cmpResult)
{
@@ -2322,11 +2151,6 @@ void MainDialog::mapGridDataToUI(GridView& output, const FileCompareResult& file
default:
assert (false);
}
-
- //hide filtered row, if corresponding option is set
- if (hideFilteredElements && !i->selectedForSynchronization)
- continue;
-
output.push_back(currentRow);
}
@@ -2476,7 +2300,7 @@ void MainDialog::removeFolderPair(bool removeAll)
CompareStatusUpdater::CompareStatusUpdater(MainDialog* dlg) :
mainDialog(dlg),
continueOnError(false),
- currentProcess(-1)
+ currentProcess(StatusHandler::PROCESS_NONE)
{
//prevent user input during "compare", do not disable maindialog since abort-button would also be disabled
//it's not nice, but works - even has the advantage that certain actions are still possible: exit, about..
@@ -2578,13 +2402,13 @@ void CompareStatusUpdater::updateStatusText(const wxString& text)
}
-void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID)
+void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, Process processID)
{
currentProcess = processID;
- if (currentProcess == FreeFileSync::scanningFilesProcess)
+ if (currentProcess == StatusHandler::PROCESS_SCANNING)
;
- else if (currentProcess == FreeFileSync::compareFileContentProcess)
+ else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT)
{
mainDialog->compareStatus->switchToCompareBytewise(objectsTotal, dataTotal);
mainDialog->Layout();
@@ -2597,18 +2421,18 @@ void CompareStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, in
inline
void CompareStatusUpdater::updateProcessedData(int objectsProcessed, double dataProcessed)
{
- if (currentProcess == FreeFileSync::scanningFilesProcess)
+ if (currentProcess == StatusHandler::PROCESS_SCANNING)
mainDialog->compareStatus->incScannedObjects_NoUpdate(objectsProcessed);
- else if (currentProcess == FreeFileSync::compareFileContentProcess)
+ else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT)
mainDialog->compareStatus->incProcessedCmpData_NoUpdate(objectsProcessed, dataProcessed);
else assert(false);
}
-int CompareStatusUpdater::reportError(const wxString& text)
+ErrorHandler::Response CompareStatusUpdater::reportError(const wxString& text)
{
if (continueOnError)
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
mainDialog->compareStatus->updateStatusPanelNow();
@@ -2621,11 +2445,11 @@ int CompareStatusUpdater::reportError(const wxString& text)
switch (rv)
{
- case ErrorDlg::continueButtonPressed:
- return StatusUpdater::continueNext;
- case ErrorDlg::retryButtonPressed:
- return StatusUpdater::retry;
- case ErrorDlg::abortButtonPressed:
+ case ErrorDlg::BUTTON_CONTINUE:
+ return ErrorHandler::CONTINUE_NEXT;
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+ case ErrorDlg::BUTTON_ABORT:
{
abortionRequested = true;
throw AbortThisProcess();
@@ -2634,7 +2458,7 @@ int CompareStatusUpdater::reportError(const wxString& text)
assert (false);
}
- return StatusUpdater::continueNext; //dummy return value
+ return ErrorHandler::CONTINUE_NEXT; //dummy return value
}
@@ -2703,9 +2527,9 @@ void SyncStatusUpdater::updateStatusText(const wxString& text)
}
-void SyncStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID)
+void SyncStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, Process processID)
{
- assert (processID == FreeFileSync::synchronizeFilesProcess);
+ assert (processID == StatusHandler::PROCESS_SYNCHRONIZING);
syncStatusFrame->resetGauge(objectsTotal, dataTotal);
syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING);
@@ -2719,12 +2543,12 @@ void SyncStatusUpdater::updateProcessedData(int objectsProcessed, double dataPro
}
-int SyncStatusUpdater::reportError(const wxString& text)
+ErrorHandler::Response SyncStatusUpdater::reportError(const wxString& text)
{
if (continueError)
{
unhandledErrors.Add(text);
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
}
wxString errorMessage = text + _("\n\nContinue with next object, retry or abort synchronization?");
@@ -2736,12 +2560,12 @@ int SyncStatusUpdater::reportError(const wxString& text)
switch (rv)
{
- case ErrorDlg::continueButtonPressed:
+ case ErrorDlg::BUTTON_CONTINUE:
unhandledErrors.Add(text);
- return StatusUpdater::continueNext;
- case ErrorDlg::retryButtonPressed:
- return StatusUpdater::retry;
- case ErrorDlg::abortButtonPressed:
+ return ErrorHandler::CONTINUE_NEXT;
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+ case ErrorDlg::BUTTON_ABORT:
{
unhandledErrors.Add(text);
abortionRequested = true;
@@ -2749,7 +2573,7 @@ int SyncStatusUpdater::reportError(const wxString& text)
}
default:
assert (false);
- return StatusUpdater::continueNext;
+ return ErrorHandler::CONTINUE_NEXT;
}
}
@@ -2824,7 +2648,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
}
else
{
- wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + fileName + wxT("\""), _("An exception occured!"), wxOK | wxICON_ERROR);
+ wxMessageBox(wxString(_("Could not write to ")) + wxT("\"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
}
}
@@ -2832,6 +2656,15 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
}
+void MainDialog::OnMenuAdjustFileTimes(wxCommandEvent& event)
+{
+ ModifyFilesDlg* modifyDlg = new ModifyFilesDlg(this, FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue()), 0);
+ modifyDlg->ShowModal();
+
+ event.Skip();
+}
+
+
void MainDialog::OnMenuBatchJob(wxCommandEvent& event)
{
vector<FolderPair> folderPairs;
@@ -2862,7 +2695,7 @@ void MainDialog::OnMenuQuit(wxCommandEvent& event)
void MainDialog::OnMenuLangEnglish(wxCommandEvent& event)
{
- programLanguage->loadLanguageFile(wxLANGUAGE_ENGLISH); //language is a global attribute
+ programLanguage->setLanguage(wxLANGUAGE_ENGLISH); //language is a global attribute
restartOnExit = true;
Destroy();
event.Skip();
@@ -2871,7 +2704,7 @@ void MainDialog::OnMenuLangEnglish(wxCommandEvent& event)
void MainDialog::OnMenuLangGerman(wxCommandEvent& event)
{
- programLanguage->loadLanguageFile(wxLANGUAGE_GERMAN); //language is a global attribute
+ programLanguage->setLanguage(wxLANGUAGE_GERMAN); //language is a global attribute
restartOnExit = true;
Destroy();
event.Skip();
@@ -2880,7 +2713,7 @@ void MainDialog::OnMenuLangGerman(wxCommandEvent& event)
void MainDialog::OnMenuLangFrench(wxCommandEvent& event)
{
- programLanguage->loadLanguageFile(wxLANGUAGE_FRENCH); //language is a global attribute
+ programLanguage->setLanguage(wxLANGUAGE_FRENCH); //language is a global attribute
restartOnExit = true;
Destroy();
event.Skip();
@@ -2889,7 +2722,16 @@ void MainDialog::OnMenuLangFrench(wxCommandEvent& event)
void MainDialog::OnMenuLangJapanese(wxCommandEvent& event)
{
- programLanguage->loadLanguageFile(wxLANGUAGE_JAPANESE); //language is a global attribute
+ programLanguage->setLanguage(wxLANGUAGE_JAPANESE); //language is a global attribute
+ restartOnExit = true;
+ Destroy();
+ event.Skip();
+}
+
+
+void MainDialog::OnMenuLangDutch(wxCommandEvent& event)
+{
+ programLanguage->setLanguage(wxLANGUAGE_DUTCH); //language is a global attribute
restartOnExit = true;
Destroy();
event.Skip();
diff --git a/ui/MainDialog.h b/ui/MainDialog.h
index 908434ea..e3f72e03 100644
--- a/ui/MainDialog.h
+++ b/ui/MainDialog.h
@@ -19,6 +19,7 @@
#include <wx/dnd.h>
#include <wx/config.h>
#include <stack>
+#include "../library/processXml.h"
using namespace std;
@@ -27,8 +28,7 @@ enum ContextItem
{
CONTEXT_FILTER_TEMP = 10,
CONTEXT_EXCLUDE_EXT,
- CONTEXT_EXCLUDE_FILE,
- CONTEXT_EXCLUDE_DIR,
+ CONTEXT_EXCLUDE_OBJ,
CONTEXT_CLIPBOARD,
CONTEXT_EXPLORER,
CONTEXT_DELETE_FILES
@@ -46,15 +46,17 @@ class MainDialog : public GuiGenerated
friend class FileDropEvent;
public:
- MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language);
+ MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale* language, xmlAccess::XmlGlobalSettings& settings);
~MainDialog();
private:
//configuration load/save
- void loadDefaultConfiguration();
bool readConfigurationFromXml(const wxString& filename, bool programStartup = false);
bool writeConfigurationToXml(const wxString& filename);
+ void readGlobalSettings();
+ void writeGlobalSettings();
+
void updateViewFilterButtons();
void updateFilterButton(wxBitmapButton* filterButton, bool isActive);
void updateCompareButtons();
@@ -65,7 +67,7 @@ private:
void removeFolderPair(bool removeAll = false);
//main method for putting gridData on UI: maps data respecting current view settings
- void writeGrid(const FileCompareResult& gridData, bool useUI_GridCache = false);
+ void writeGrid(const FileCompareResult& gridData);
void mapGridDataToUI(GridView& output, const FileCompareResult& fileCmpResult);
void updateStatusInformation(const GridView& output);
@@ -138,6 +140,7 @@ private:
//menu events
void OnMenuExportFileList( wxCommandEvent& event);
+ void OnMenuAdjustFileTimes( wxCommandEvent& event);
void OnMenuBatchJob( wxCommandEvent& event);
void OnMenuAbout( wxCommandEvent& event);
void OnMenuQuit( wxCommandEvent& event);
@@ -145,11 +148,15 @@ private:
void OnMenuLangGerman( wxCommandEvent& event);
void OnMenuLangFrench( wxCommandEvent& event);
void OnMenuLangJapanese( wxCommandEvent& event);
+ void OnMenuLangDutch( wxCommandEvent& event);
void enableSynchronization(bool value);
//***********************************************
- //global application variables are stored here:
+ //application variables are stored here:
+
+ //global settings used by GUI and batch mode
+ xmlAccess::XmlGlobalSettings& globalSettings;
//technical representation of grid-data
FileCompareResult currentGridData;
@@ -205,9 +212,14 @@ private:
bool filteringInitialized;
bool filteringPending;
+ //temporal variables used by exclude via context menu
wxString exFilterCandidateExtension;
- wxString exFilterCandidateFilename;
- wxString exFilterCandidateDirname;
+ struct FilterObject
+ {
+ wxString relativeName;
+ FileDescrLine::ObjectType type;
+ };
+ vector<FilterObject> exFilterCandidateObj;
bool synchronizationEnabled; //determines whether synchronization should be allowed
@@ -241,16 +253,16 @@ private:
//classes handling sync and compare error as well as status information
-class CompareStatusUpdater : public StatusUpdater
+class CompareStatusUpdater : public StatusHandler
{
public:
CompareStatusUpdater(MainDialog* dlg);
~CompareStatusUpdater();
void updateStatusText(const wxString& text);
- void initNewProcess(int objectsTotal, double dataTotal, int processID);
+ void initNewProcess(int objectsTotal, double dataTotal, Process processID);
void updateProcessedData(int objectsProcessed, double dataProcessed);
- int reportError(const wxString& text);
+ ErrorHandler::Response reportError(const wxString& text);
void forceUiRefresh();
@@ -259,20 +271,20 @@ private:
MainDialog* mainDialog;
bool continueOnError;
- int currentProcess;
+ Process currentProcess;
};
-class SyncStatusUpdater : public StatusUpdater
+class SyncStatusUpdater : public StatusHandler
{
public:
SyncStatusUpdater(wxWindow* dlg, bool continueOnError);
~SyncStatusUpdater();
void updateStatusText(const wxString& text);
- void initNewProcess(int objectsTotal, double dataTotal, int processID);
+ void initNewProcess(int objectsTotal, double dataTotal, Process processID);
void updateProcessedData(int objectsProcessed, double dataProcessed);
- int reportError(const wxString& text);
+ ErrorHandler::Response reportError(const wxString& text);
void forceUiRefresh();
diff --git a/ui/SmallDialogs.cpp b/ui/SmallDialogs.cpp
index fd09e17a..0886bb03 100644
--- a/ui/SmallDialogs.cpp
+++ b/ui/SmallDialogs.cpp
@@ -1,7 +1,7 @@
#include "smallDialogs.h"
#include "../library/globalFunctions.h"
-//#include <fstream>
#include "../library/resources.h"
+#include <wx/msgdlg.h>
using namespace globalFunctions;
@@ -150,7 +150,7 @@ void FilterDlg::OnOK(wxCommandEvent& event)
excludeFilter = m_textCtrlExclude->GetValue();
//when leaving dialog: filter and redraw grid, if filter is active
- EndModal(okayButtonPressed);
+ EndModal(BUTTON_OKAY);
}
@@ -181,29 +181,29 @@ DeleteDialog::~DeleteDialog() {}
void DeleteDialog::OnOK(wxCommandEvent& event)
{
- EndModal(okayButtonPressed);
+ EndModal(BUTTON_OKAY);
}
void DeleteDialog::OnCancel(wxCommandEvent& event)
{
- EndModal(cancelButtonPressed);
+ EndModal(BUTTON_CANCEL);
}
void DeleteDialog::OnClose(wxCloseEvent& event)
{
- EndModal(cancelButtonPressed);
+ EndModal(BUTTON_CANCEL);
}
//########################################################################################
ErrorDlg::ErrorDlg(const wxString messageText, bool& continueError) :
- ErrorDlgGenerated(0),
+ ErrorDlgGenerated(NULL),
continueOnError(continueError)
{
m_bitmap10->SetBitmap(*globalResource.bitmapWarning);
m_textCtrl8->SetValue(messageText);
- m_buttonContinue->SetFocus();
+ m_buttonRetry->SetFocus();
}
ErrorDlg::~ErrorDlg() {}
@@ -212,31 +212,156 @@ ErrorDlg::~ErrorDlg() {}
void ErrorDlg::OnClose(wxCloseEvent& event)
{
//continueOnError = m_checkBoxContinueError->GetValue(); -> not needed here
- EndModal(abortButtonPressed);
+ EndModal(BUTTON_ABORT);
}
void ErrorDlg::OnContinue(wxCommandEvent& event)
{
continueOnError = m_checkBoxContinueError->GetValue();
- EndModal(continueButtonPressed);
+ EndModal(BUTTON_CONTINUE);
}
void ErrorDlg::OnRetry(wxCommandEvent& event)
{
//continueOnError = m_checkBoxContinueError->GetValue(); -> not needed here
- EndModal(retryButtonPressed);
+ EndModal(BUTTON_RETRY);
}
void ErrorDlg::OnAbort(wxCommandEvent& event)
{
//continueOnError = m_checkBoxContinueError->GetValue(); -> not needed here
- EndModal(abortButtonPressed);
+ EndModal(BUTTON_ABORT);
}
+
+
//########################################################################################
+ModifyFilesDlg::ModifyFilesDlg(wxWindow* window, const wxString& parentDirectory, const int timeShift) :
+ ModifyFilesDlgGenerated(window)
+{
+ m_dirPicker->SetPath(parentDirectory);
+ m_textCtrlDirectory->SetValue(parentDirectory);
+ m_spinCtrlTimeShift->SetValue(timeShift);
+
+ m_buttonApply->SetFocus();
+}
+
+
+ModifyFilesDlg::~ModifyFilesDlg() {}
+
+
+class ModifyErrorHandler : public ErrorHandler
+{
+public:
+ ModifyErrorHandler(bool& unsolvedErrorOccured) :
+ continueOnError(false),
+ unsolvedErrors(unsolvedErrorOccured) {}
+
+ ~ModifyErrorHandler() {}
+
+ Response reportError(const wxString& text)
+ {
+ if (continueOnError)
+ {
+ unsolvedErrors = true;
+ return ErrorHandler::CONTINUE_NEXT;
+ }
+
+ ErrorDlg* errorDlg = new ErrorDlg(text, continueOnError);
+
+ int rv = errorDlg->ShowModal();
+ errorDlg->Destroy();
+ switch (rv)
+ {
+ case ErrorDlg::BUTTON_CONTINUE:
+ unsolvedErrors = true;
+ return ErrorHandler::CONTINUE_NEXT;
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+ case ErrorDlg::BUTTON_ABORT:
+ {
+ unsolvedErrors = true;
+ throw AbortThisProcess();
+ }
+ default:
+ assert (false);
+ }
+
+ return ErrorHandler::CONTINUE_NEXT; //dummy return value
+ }
+private:
+
+ bool continueOnError;
+ bool& unsolvedErrors;
+};
+
+
+void ModifyFilesDlg::OnApply(wxCommandEvent& event)
+{
+ const int timeToShift = m_spinCtrlTimeShift->GetValue();
+ const wxString parentDir = m_textCtrlDirectory->GetValue();
+
+ if (!wxDirExists(parentDir))
+ {
+ 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
+ {
+ ModifyErrorHandler errorHandler(unsolvedErrorOccured);
+ FreeFileSync::adjustModificationTimes(parentDir, timeToShift, &errorHandler);
+ }
+ catch (const AbortThisProcess& theException)
+ {
+ EndModal(0);
+ }
+
+ if (unsolvedErrorOccured)
+ wxMessageBox(_("Unresolved errors occured during operation!"), _("Info"), wxOK);
+ else
+ wxMessageBox(_("All file times have been adjusted successfully!"), _("Info"), wxOK);
+ EndModal(0);
+}
+
+
+void ModifyFilesDlg::OnCancel(wxCommandEvent& event)
+{
+ EndModal(0);
+}
+
+
+void ModifyFilesDlg::OnClose(wxCloseEvent& event)
+{
+ EndModal(0);
+}
+
+
+void ModifyFilesDlg::OnWriteDirManually(wxCommandEvent& event)
+{
+ wxString newDir = FreeFileSync::getFormattedDirectoryName(event.GetString());
+ if (wxDirExists(newDir))
+ m_dirPicker->SetPath(newDir);
+
+ event.Skip();
+}
+
+
+void ModifyFilesDlg::OnDirSelected(wxFileDirPickerEvent& event)
+{
+ const wxString newPath = event.GetPath();
+ m_textCtrlDirectory->SetValue(newPath);
+
+ event.Skip();
+}
+
+
+
+//########################################################################################
/*
class for calculation of remaining time:
----------------------------------------
@@ -330,9 +455,9 @@ wxLongLong RemainingTime::getRemainingTime(double processedDataSinceLastCall, in
//########################################################################################
-SyncStatus::SyncStatus(StatusUpdater* updater, wxWindow* parentWindow) :
+SyncStatus::SyncStatus(StatusHandler* updater, wxWindow* parentWindow) :
SyncStatusDlgGenerated(parentWindow),
- currentStatusUpdater(updater),
+ currentStatusHandler(updater),
windowToDis(parentWindow),
currentProcessIsRunning(true),
totalData(0),
@@ -403,18 +528,23 @@ void SyncStatus::updateStatusDialogNow()
m_gauge1->SetValue(int(currentData * scalingFactor));
//status text
- m_textCtrlInfo->SetValue(currentStatusText);
+ if (m_textCtrlInfo->GetValue() != currentStatusText) //avoid screen flicker
+ m_textCtrlInfo->SetValue(currentStatusText);
//remaining objects
- m_staticTextRemainingObj->SetLabel(numberToWxString(totalObjects - currentObjects));
-
+ const wxString remainingObjTmp = numberToWxString(totalObjects - currentObjects);
+ if (m_staticTextRemainingObj->GetLabel() != remainingObjTmp) //avoid screen flicker
+ m_staticTextRemainingObj->SetLabel(remainingObjTmp);
//remaining bytes left for copy
- const wxString remainingBytes = FreeFileSync::formatFilesizeToShortString(totalData - currentData);
- m_staticTextDataRemaining->SetLabel(remainingBytes);
+ const wxString remainingBytesTmp = FreeFileSync::formatFilesizeToShortString(totalData - currentData);
+ if (m_staticTextDataRemaining->GetLabel() != remainingBytesTmp) //avoid screen flicker
+ m_staticTextDataRemaining->SetLabel(remainingBytesTmp);
//time elapsed
- m_staticTextTimeElapsed->SetLabel((wxTimeSpan::Milliseconds(timeElapsed.Time())).Format());
+ const wxString timeElapsedTmp = (wxTimeSpan::Milliseconds(timeElapsed.Time())).Format();
+ if (m_staticTextTimeElapsed->GetLabel() != timeElapsedTmp) //avoid screen flicker
+ m_staticTextTimeElapsed->SetLabel(timeElapsedTmp);
//do the ui update
bSizer28->Layout();
@@ -472,8 +602,8 @@ void SyncStatus::setCurrentStatus(SyncStatusID id)
}
-void SyncStatus::processHasFinished(SyncStatusID id) //essential to call this in StatusUpdater derived class destructor
-{ //at the LATEST(!) to prevent access to currentStatusUpdater
+void SyncStatus::processHasFinished(SyncStatusID id) //essential to call this in StatusHandler derived class destructor
+{ //at the LATEST(!) to prevent access to currentStatusHandler
currentProcessIsRunning = false; //enable okay and close events; may be set ONLY in this method
setCurrentStatus(id);
@@ -532,7 +662,7 @@ void SyncStatus::OnAbort(wxCommandEvent& event)
setStatusText_NoUpdate(_("Abort requested: Waiting for current operation to finish..."));
//no Layout() or UI-update here to avoid cascaded Yield()-call
- currentStatusUpdater->requestAbortion();
+ currentStatusHandler->requestAbortion();
}
}
@@ -540,7 +670,8 @@ void SyncStatus::OnAbort(wxCommandEvent& event)
void SyncStatus::OnClose(wxCloseEvent& event)
{
processPaused = false;
- if (currentProcessIsRunning) currentStatusUpdater->requestAbortion();
+ if (currentProcessIsRunning)
+ currentStatusHandler->requestAbortion();
else
Destroy();
}
@@ -635,19 +766,26 @@ void CompareStatus::setStatusText_NoUpdate(const wxString& text)
void CompareStatus::updateStatusPanelNow()
{
//status texts
- m_textCtrlFilename->SetValue(currentStatusText);
+ if (m_textCtrlFilename->GetValue() != currentStatusText) //avoid screen flicker
+ m_textCtrlFilename->SetValue(currentStatusText);
- m_staticTextScanned->SetLabel(numberToWxString(scannedObjects));
+ //nr of scanned objects
+ const wxString scannedObjTmp = numberToWxString(scannedObjects);
+ if (m_staticTextScanned->GetLabel() != scannedObjTmp) //avoid screen flicker
+ m_staticTextScanned->SetLabel(scannedObjTmp);
//progress indicator for "compare file content"
m_gauge2->SetValue(int(processedCmpData * scalingFactorCmp));
- //remaining file to compare
- m_staticTextFilesToCompare->SetLabel(numberToWxString(totalCmpObjects - processedCmpObjects));
+ //remaining files left for file comparison
+ const wxString filesToCompareTmp = numberToWxString(totalCmpObjects - processedCmpObjects);
+ if (m_staticTextFilesToCompare->GetLabel() != filesToCompareTmp) //avoid screen flicker
+ m_staticTextFilesToCompare->SetLabel(filesToCompareTmp);
//remaining bytes left for file comparison
- const wxString remainingBytes = FreeFileSync::formatFilesizeToShortString(totalCmpData - processedCmpData);
- m_staticTextDataToCompare->SetLabel(remainingBytes);
+ const wxString remainingBytesTmp = FreeFileSync::formatFilesizeToShortString(totalCmpData - processedCmpData);
+ if (m_staticTextDataToCompare->GetLabel() != remainingBytesTmp) //avoid screen flicker
+ m_staticTextDataToCompare->SetLabel(remainingBytesTmp);
/*
//remaining time in seconds
@@ -659,7 +797,9 @@ void CompareStatus::updateStatusPanelNow()
*/
//time elapsed
- m_staticTextTimeElapsed->SetLabel((wxTimeSpan::Milliseconds(timeElapsed.Time())).Format());
+ const wxString timeElapsedTmp = (wxTimeSpan::Milliseconds(timeElapsed.Time())).Format();
+ if (m_staticTextTimeElapsed->GetLabel() != timeElapsedTmp) //avoid screen flicker
+ m_staticTextTimeElapsed->SetLabel(timeElapsedTmp);
//do the ui update
bSizer42->Layout();
diff --git a/ui/SmallDialogs.h b/ui/SmallDialogs.h
index b70e6105..7efb4dbe 100644
--- a/ui/SmallDialogs.h
+++ b/ui/SmallDialogs.h
@@ -35,7 +35,10 @@ public:
FilterDlg(wxWindow* window, wxString& filterIncl, wxString& filterExcl);
~FilterDlg();
- static const int okayButtonPressed = 25;
+ enum
+ {
+ BUTTON_OKAY
+ };
private:
void OnHelp(wxCommandEvent& event);
@@ -55,8 +58,11 @@ public:
DeleteDialog(const wxString& headerText, const wxString& messageText, wxWindow* main);
~DeleteDialog();
- static const int okayButtonPressed = 35;
- static const int cancelButtonPressed = 45;
+ enum
+ {
+ BUTTON_OKAY,
+ BUTTON_CANCEL
+ };
private:
void OnOK(wxCommandEvent& event);
@@ -71,9 +77,12 @@ public:
ErrorDlg(const wxString messageText, bool& continueError);
~ErrorDlg();
- static const int continueButtonPressed = 35;
- static const int retryButtonPressed = 45;
- static const int abortButtonPressed = 55;
+ enum
+ {
+ BUTTON_CONTINUE,
+ BUTTON_RETRY,
+ BUTTON_ABORT
+ };
private:
void OnClose(wxCloseEvent& event);
@@ -85,10 +94,26 @@ private:
};
+class ModifyFilesDlg : public ModifyFilesDlgGenerated
+{
+public:
+ ModifyFilesDlg(wxWindow* window, const wxString& parentDirectory, const int timeShift);
+ ~ModifyFilesDlg();
+
+private:
+ void OnApply(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+ void OnClose(wxCloseEvent& event);
+
+ void OnWriteDirManually(wxCommandEvent& event);
+ void OnDirSelected(wxFileDirPickerEvent& event);
+};
+
+
class SyncStatus : public SyncStatusDlgGenerated
{
public:
- SyncStatus(StatusUpdater* updater, wxWindow* parentWindow = NULL);
+ SyncStatus(StatusHandler* updater, wxWindow* parentWindow = NULL);
~SyncStatus();
enum SyncStatusID
@@ -118,7 +143,7 @@ private:
wxStopWatch timeElapsed;
- StatusUpdater* currentStatusUpdater;
+ StatusHandler* currentStatusHandler;
wxWindow* windowToDis;
bool currentProcessIsRunning;
diff --git a/ui/SyncDialog.cpp b/ui/SyncDialog.cpp
index ad1c1a21..7a1d4602 100644
--- a/ui/SyncDialog.cpp
+++ b/ui/SyncDialog.cpp
@@ -31,11 +31,11 @@ SyncDialog::SyncDialog(wxWindow* window,
//set icons for this dialog
m_bpButton18->SetBitmapLabel(*globalResource.bitmapStartSync);
m_bpButton18->SetBitmapDisabled(*globalResource.bitmapStartSyncDis);
- m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnlyDeact);
- m_bitmap14->SetBitmap(*globalResource.bitmapRightOnlyDeact);
- m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewerDeact);
- m_bitmap16->SetBitmap(*globalResource.bitmapRightNewerDeact);
- m_bitmap17->SetBitmap(*globalResource.bitmapDifferentDeact);
+ m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnly);
+ m_bitmap14->SetBitmap(*globalResource.bitmapRightOnly);
+ m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewer);
+ m_bitmap16->SetBitmap(*globalResource.bitmapRightNewer);
+ m_bitmap17->SetBitmap(*globalResource.bitmapDifferent);
if (synchronizationEnabled)
m_bpButton18->Enable();
@@ -46,18 +46,18 @@ SyncDialog::SyncDialog(wxWindow* window,
}
//set radiobutton
- if (localSyncConfiguration.exLeftSideOnly == SYNC_DIR_RIGHT &&
- localSyncConfiguration.exRightSideOnly == SYNC_DIR_RIGHT &&
- localSyncConfiguration.leftNewer == SYNC_DIR_RIGHT &&
- localSyncConfiguration.rightNewer == SYNC_DIR_RIGHT &&
- localSyncConfiguration.different == SYNC_DIR_RIGHT)
+ if ( localSyncConfiguration.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.rightNewer == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.different == SyncConfiguration::SYNC_DIR_RIGHT)
m_radioBtn1->SetValue(true); //one way ->
- else if (localSyncConfiguration.exLeftSideOnly == SYNC_DIR_RIGHT &&
- localSyncConfiguration.exRightSideOnly == SYNC_DIR_LEFT &&
- localSyncConfiguration.leftNewer == SYNC_DIR_RIGHT &&
- localSyncConfiguration.rightNewer == SYNC_DIR_LEFT &&
- localSyncConfiguration.different == SYNC_DIR_NONE)
+ else if (localSyncConfiguration.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.exRightSideOnly == SyncConfiguration::SYNC_DIR_LEFT &&
+ localSyncConfiguration.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT &&
+ localSyncConfiguration.rightNewer == SyncConfiguration::SYNC_DIR_LEFT &&
+ localSyncConfiguration.different == SyncConfiguration::SYNC_DIR_NONE)
m_radioBtn2->SetValue(true); //two way <->
else
@@ -81,81 +81,81 @@ void SyncDialog::updateConfigIcons(wxBitmapButton* button1,
wxBitmapButton* button5,
const SyncConfiguration& syncConfig)
{
- if (syncConfig.exLeftSideOnly == SYNC_DIR_RIGHT)
+ if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT)
{
button1->SetBitmapLabel(*globalResource.bitmapArrowRightCr);
button1->SetToolTip(_("Copy from left to right"));
}
- else if (syncConfig.exLeftSideOnly == SYNC_DIR_LEFT)
+ else if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_LEFT)
{
button1->SetBitmapLabel(*globalResource.bitmapDeleteLeft);
button1->SetToolTip(_("Delete files/folders existing on left side only"));
}
- else if (syncConfig.exLeftSideOnly == SYNC_DIR_NONE)
+ else if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_NONE)
{
button1->SetBitmapLabel(*globalResource.bitmapArrowNone);
button1->SetToolTip(_("Do nothing"));
}
- if (syncConfig.exRightSideOnly == SYNC_DIR_RIGHT)
+ if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT)
{
button2->SetBitmapLabel(*globalResource.bitmapDeleteRight);
button2->SetToolTip(_("Delete files/folders existing on right side only"));
}
- else if (syncConfig.exRightSideOnly == SYNC_DIR_LEFT)
+ else if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_LEFT)
{
button2->SetBitmapLabel(*globalResource.bitmapArrowLeftCr);
button2->SetToolTip(_("Copy from right to left"));
}
- else if (syncConfig.exRightSideOnly == SYNC_DIR_NONE)
+ else if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_NONE)
{
button2->SetBitmapLabel(*globalResource.bitmapArrowNone);
button2->SetToolTip(_("Do nothing"));
}
- if (syncConfig.leftNewer == SYNC_DIR_RIGHT)
+ if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT)
{
button3->SetBitmapLabel(*globalResource.bitmapArrowRight);
button3->SetToolTip(_("Copy from left to right overwriting"));
}
- else if (syncConfig.leftNewer == SYNC_DIR_LEFT)
+ else if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_LEFT)
{
button3->SetBitmapLabel(*globalResource.bitmapArrowLeft);
button3->SetToolTip(_("Copy from right to left overwriting"));
}
- else if (syncConfig.leftNewer == SYNC_DIR_NONE)
+ else if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_NONE)
{
button3->SetBitmapLabel(*globalResource.bitmapArrowNone);
button3->SetToolTip(_("Do nothing"));
}
- if (syncConfig.rightNewer == SYNC_DIR_RIGHT)
+ if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_RIGHT)
{
button4->SetBitmapLabel(*globalResource.bitmapArrowRight);
button4->SetToolTip(_("Copy from left to right overwriting"));
}
- else if (syncConfig.rightNewer == SYNC_DIR_LEFT)
+ else if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_LEFT)
{
button4->SetBitmapLabel(*globalResource.bitmapArrowLeft);
button4->SetToolTip(_("Copy from right to left overwriting"));
}
- else if (syncConfig.rightNewer == SYNC_DIR_NONE)
+ else if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_NONE)
{
button4->SetBitmapLabel(*globalResource.bitmapArrowNone);
button4->SetToolTip(_("Do nothing"));
}
- if (syncConfig.different == SYNC_DIR_RIGHT)
+ if (syncConfig.different == SyncConfiguration::SYNC_DIR_RIGHT)
{
button5->SetBitmapLabel(*globalResource.bitmapArrowRight);
button5->SetToolTip(_("Copy from left to right overwriting"));
}
- else if (syncConfig.different == SYNC_DIR_LEFT)
+ else if (syncConfig.different == SyncConfiguration::SYNC_DIR_LEFT)
{
button5->SetBitmapLabel(*globalResource.bitmapArrowLeft);
button5->SetToolTip(_("Copy from right to left overwriting"));
}
- else if (syncConfig.different == SYNC_DIR_NONE)
+ else if (syncConfig.different == SyncConfiguration::SYNC_DIR_NONE)
{
button5->SetBitmapLabel(*globalResource.bitmapArrowNone);
button5->SetToolTip(_("Do nothing"));
@@ -257,11 +257,11 @@ void SyncDialog::OnSelectRecycleBin(wxCommandEvent& event)
void SyncDialog::OnSyncLeftToRight(wxCommandEvent& event)
{
- localSyncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT;
- localSyncConfiguration.exRightSideOnly = SYNC_DIR_RIGHT;
- localSyncConfiguration.leftNewer = SYNC_DIR_RIGHT;
- localSyncConfiguration.rightNewer = SYNC_DIR_RIGHT;
- localSyncConfiguration.different = SYNC_DIR_RIGHT;
+ localSyncConfiguration.exLeftSideOnly = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.exRightSideOnly = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.leftNewer = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.rightNewer = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.different = SyncConfiguration::SYNC_DIR_RIGHT;
updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration);
calculatePreview();
@@ -273,11 +273,11 @@ void SyncDialog::OnSyncLeftToRight(wxCommandEvent& event)
void SyncDialog::OnSyncBothSides(wxCommandEvent& event)
{
- localSyncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT;
- localSyncConfiguration.exRightSideOnly = SYNC_DIR_LEFT;
- localSyncConfiguration.leftNewer = SYNC_DIR_RIGHT;
- localSyncConfiguration.rightNewer = SYNC_DIR_LEFT;
- localSyncConfiguration.different = SYNC_DIR_NONE;
+ localSyncConfiguration.exLeftSideOnly = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.exRightSideOnly = SyncConfiguration::SYNC_DIR_LEFT;
+ localSyncConfiguration.leftNewer = SyncConfiguration::SYNC_DIR_RIGHT;
+ localSyncConfiguration.rightNewer = SyncConfiguration::SYNC_DIR_LEFT;
+ localSyncConfiguration.different = SyncConfiguration::SYNC_DIR_NONE;
updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration);
calculatePreview();
@@ -287,14 +287,14 @@ void SyncDialog::OnSyncBothSides(wxCommandEvent& event)
}
-void toggleSyncDirection(SyncDirection& current)
+void toggleSyncDirection(SyncConfiguration::Direction& current)
{
- if (current == SYNC_DIR_RIGHT)
- current = SYNC_DIR_LEFT;
- else if (current == SYNC_DIR_LEFT)
- current = SYNC_DIR_NONE;
- else if (current== SYNC_DIR_NONE)
- current = SYNC_DIR_RIGHT;
+ if (current == SyncConfiguration::SYNC_DIR_RIGHT)
+ current = SyncConfiguration::SYNC_DIR_LEFT;
+ else if (current == SyncConfiguration::SYNC_DIR_LEFT)
+ current = SyncConfiguration::SYNC_DIR_NONE;
+ else if (current== SyncConfiguration::SYNC_DIR_NONE)
+ current = SyncConfiguration::SYNC_DIR_RIGHT;
else
assert (false);
}
@@ -403,11 +403,11 @@ BatchDialog::BatchDialog(wxWindow* window,
//set icons for this dialog
- m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnlyDeact);
- m_bitmap14->SetBitmap(*globalResource.bitmapRightOnlyDeact);
- m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewerDeact);
- m_bitmap16->SetBitmap(*globalResource.bitmapRightNewerDeact);
- m_bitmap17->SetBitmap(*globalResource.bitmapDifferentDeact);
+ m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnly);
+ m_bitmap14->SetBitmap(*globalResource.bitmapRightOnly);
+ m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewer);
+ m_bitmap16->SetBitmap(*globalResource.bitmapRightNewer);
+ m_bitmap17->SetBitmap(*globalResource.bitmapDifferent);
m_bitmap8->SetBitmap(*globalResource.bitmapInclude);
m_bitmap9->SetBitmap(*globalResource.bitmapExclude);
@@ -542,31 +542,28 @@ void BatchDialog::OnCreateBatchJob(wxCommandEvent& event)
//create batch file
if (createBatchFile(fileName))
EndModal(batchFileCreated);
- else
- wxMessageBox(wxString(_("Could not create file ")) + wxT("\"") + fileName + wxT("\""), _("Error"), wxOK | wxICON_ERROR);
}
}
bool BatchDialog::createBatchFile(const wxString& filename)
{
- XmlOutput outputFile(filename, XML_BATCH_CONFIG);
+ XmlBatchConfig batchCfg;
//load structure with basic settings "mainCfg"
- XmlMainConfig mainCfg;
if (m_radioBtnSizeDate->GetValue())
- mainCfg.cfg.compareVar = CMP_BY_TIME_SIZE;
+ batchCfg.mainCfg.compareVar = CMP_BY_TIME_SIZE;
else if (m_radioBtnContent->GetValue())
- mainCfg.cfg.compareVar = CMP_BY_CONTENT;
+ batchCfg.mainCfg.compareVar = CMP_BY_CONTENT;
else
return false;
- mainCfg.cfg.syncConfiguration = localSyncConfiguration;
- mainCfg.cfg.filterIsActive = filterIsActive;
- mainCfg.cfg.includeFilter = m_textCtrlInclude->GetValue();
- mainCfg.cfg.excludeFilter = m_textCtrlExclude->GetValue();
- mainCfg.cfg.useRecycleBin = m_checkBoxUseRecycler->GetValue();
- mainCfg.cfg.continueOnError = m_checkBoxContinueError->GetValue();
+ batchCfg.mainCfg.syncConfiguration = localSyncConfiguration;
+ batchCfg.mainCfg.filterIsActive = filterIsActive;
+ batchCfg.mainCfg.includeFilter = m_textCtrlInclude->GetValue();
+ batchCfg.mainCfg.excludeFilter = m_textCtrlExclude->GetValue();
+ batchCfg.mainCfg.useRecycleBin = m_checkBoxUseRecycler->GetValue();
+ batchCfg.mainCfg.continueOnError = m_checkBoxContinueError->GetValue();
for (unsigned int i = 0; i < localFolderPairs.size(); ++i)
{
@@ -574,20 +571,23 @@ bool BatchDialog::createBatchFile(const wxString& filename)
newPair.leftDirectory = localFolderPairs[i]->m_directoryLeft->GetValue();
newPair.rightDirectory = localFolderPairs[i]->m_directoryRight->GetValue();
- mainCfg.directoryPairs.push_back(newPair);
+ batchCfg.directoryPairs.push_back(newPair);
}
//load structure with batch settings "batchCfg"
- XmlBatchConfig batchCfg;
batchCfg.silent = m_checkBoxSilent->GetValue();
- //populate and write XML tree
- if ( !outputFile.writeXmlMainConfig(mainCfg) || //add basic configuration settings
- !outputFile.writeXmlBatchConfig(batchCfg) || //add batch configuration settings
- !outputFile.writeToFile()) //save XML
+ //write config to XML
+ try
+ {
+ xmlAccess::writeBatchConfig(filename, batchCfg);
+ }
+ catch (const FileError& error)
+ {
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
return false;
- else
- return true;
+ }
+ return true;
}
diff --git a/ui/guiGenerated.cpp b/ui/guiGenerated.cpp
index 06f82d9f..e78dc2e9 100644
--- a/ui/guiGenerated.cpp
+++ b/ui/guiGenerated.cpp
@@ -17,6 +17,16 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
m_menubar1 = new wxMenuBar( 0 );
m_menu1 = new wxMenu();
+ wxMenuItem* m_menuItem10;
+ m_menuItem10 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("1. &Compare") ) + wxT('\t') + wxT("ALT-C"), wxEmptyString, wxITEM_NORMAL );
+ m_menu1->Append( m_menuItem10 );
+
+ wxMenuItem* m_menuItem11;
+ m_menuItem11 = new wxMenuItem( m_menu1, wxID_ANY, wxString( _("2. &Synchronize...") ) + wxT('\t') + wxT("ALT-S"), wxEmptyString, wxITEM_NORMAL );
+ m_menu1->Append( m_menuItem11 );
+
+ m_menu1->AppendSeparator();
+
wxMenuItem* m_menuItem4;
m_menuItem4 = new wxMenuItem( m_menu1, wxID_EXIT, wxString( _("&Quit") ) + wxT('\t') + wxT("CTRL-Q"), wxEmptyString, wxITEM_NORMAL );
m_menu1->Append( m_menuItem4 );
@@ -24,20 +34,19 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
m_menubar1->Append( m_menu1, _("&File") );
m_menu3 = new wxMenu();
- wxMenuItem* m_menuItem5;
- m_menuItem5 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Export file list") ) , wxEmptyString, wxITEM_NORMAL );
- m_menu3->Append( m_menuItem5 );
-
m_menu31 = new wxMenu();
- m_menuItemEnglish = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("English") ) , wxEmptyString, wxITEM_RADIO );
- m_menu31->Append( m_menuItemEnglish );
-
m_menuItemGerman = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Deutsch") ) , wxEmptyString, wxITEM_RADIO );
m_menu31->Append( m_menuItemGerman );
+ m_menuItemEnglish = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("English") ) , wxEmptyString, wxITEM_RADIO );
+ m_menu31->Append( m_menuItemEnglish );
+
m_menuItemFrench = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Français") ) , wxEmptyString, wxITEM_RADIO );
m_menu31->Append( m_menuItemFrench );
+ m_menuItemDutch = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("Nederlands") ) , wxEmptyString, wxITEM_RADIO );
+ m_menu31->Append( m_menuItemDutch );
+
m_menuItemJapanese = new wxMenuItem( m_menu31, wxID_ANY, wxString( _("日本語") ) , wxEmptyString, wxITEM_RADIO );
m_menu31->Append( m_menuItemJapanese );
@@ -45,10 +54,18 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
m_menu3->AppendSeparator();
+ wxMenuItem* m_menuItem9;
+ m_menuItem9 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Adjust file times") ) , wxEmptyString, wxITEM_NORMAL );
+ m_menu3->Append( m_menuItem9 );
+
wxMenuItem* m_menuItem7;
m_menuItem7 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Create batch job") ) , wxEmptyString, wxITEM_NORMAL );
m_menu3->Append( m_menuItem7 );
+ wxMenuItem* m_menuItem5;
+ m_menuItem5 = new wxMenuItem( m_menu3, wxID_ANY, wxString( _("&Export file list") ) , wxEmptyString, wxITEM_NORMAL );
+ m_menu3->Append( m_menuItem5 );
+
m_menubar1->Append( m_menu3, _("&Advanced") );
m_menu2 = new wxMenu();
@@ -101,7 +118,7 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
m_radioBtnSizeDate = new wxRadioButton( m_panel71, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, 0 );
m_radioBtnSizeDate->SetValue( true );
- m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time (UTC) and date\nare the same.") );
+ m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time and date\nare the same.") );
bSizer45->Add( m_radioBtnSizeDate, 0, 0, 5 );
@@ -420,45 +437,21 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
sbSizer31->Add( 0, 0, 1, wxEXPAND, 5 );
m_bpButtonLeftOnly = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonLeftOnly->SetToolTip( _("Show files that exist on left side only") );
-
- m_bpButtonLeftOnly->SetToolTip( _("Show files that exist on left side only") );
-
sbSizer31->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonLeftNewer = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonLeftNewer->SetToolTip( _("Show files that are newer on left") );
-
- m_bpButtonLeftNewer->SetToolTip( _("Show files that are newer on left") );
-
sbSizer31->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonEqual = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonEqual->SetToolTip( _("Show files that are equal") );
-
- m_bpButtonEqual->SetToolTip( _("Show files that are equal") );
-
sbSizer31->Add( m_bpButtonEqual, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonDifferent = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonDifferent->SetToolTip( _("Show files that are different") );
-
- m_bpButtonDifferent->SetToolTip( _("Show files that are different") );
-
sbSizer31->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonRightNewer = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonRightNewer->SetToolTip( _("Show files that are newer on right") );
-
- m_bpButtonRightNewer->SetToolTip( _("Show files that are newer on right") );
-
sbSizer31->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bpButtonRightOnly = new wxBitmapButton( m_panel12, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW );
- m_bpButtonRightOnly->SetToolTip( _("Show files that exist on right side only") );
-
- m_bpButtonRightOnly->SetToolTip( _("Show files that exist on right side only") );
-
sbSizer31->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_VERTICAL, 5 );
@@ -557,13 +550,17 @@ GuiGenerated::GuiGenerated( wxWindow* parent, wxWindowID id, const wxString& tit
// 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_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuQuit ) );
- this->Connect( m_menuItem5->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuExportFileList ) );
- this->Connect( m_menuItemEnglish->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangEnglish ) );
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_menuItem9->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuAdjustFileTimes ) );
this->Connect( m_menuItem7->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuBatchJob ) );
+ 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 );
@@ -604,13 +601,17 @@ GuiGenerated::~GuiGenerated()
{
// 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::OnMenuQuit ) );
- this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuExportFileList ) );
- this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuLangEnglish ) );
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::OnMenuAdjustFileTimes ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GuiGenerated::OnMenuBatchJob ) );
+ 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 );
@@ -737,7 +738,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_staticText54->Wrap( 380 );
m_staticText54->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxT("Tahoma") ) );
- bSizer69->Add( m_staticText54, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ bSizer69->Add( m_staticText54, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
bSizer69->Add( 0, 5, 0, 0, 5 );
@@ -777,7 +778,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_radioBtnSizeDate = new wxRadioButton( this, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, 0 );
m_radioBtnSizeDate->SetValue( true );
- m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time (UTC) and date\nare the same.") );
+ m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time and date\nare the same.") );
sbSizer6->Add( m_radioBtnSizeDate, 0, 0, 5 );
@@ -975,7 +976,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer69->Add( bSizer68, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
- bSizer54->Add( bSizer69, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ bSizer54->Add( bSizer69, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
this->SetSizer( bSizer54 );
this->Layout();
@@ -1705,7 +1706,7 @@ HelpDlgGenerated::HelpDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_staticText56->Wrap( -1 );
m_staticText56->SetFont( wxFont( 16, 74, 90, 92, false, wxT("Tahoma") ) );
- bSizer72->Add( m_staticText56, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
+ bSizer72->Add( m_staticText56, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer72->Add( 20, 0, 0, 0, 5 );
@@ -1922,7 +1923,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_scrolledWindow3 = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxDOUBLE_BORDER|wxHSCROLL|wxVSCROLL );
m_scrolledWindow3->SetScrollRate( 5, 5 );
m_scrolledWindow3->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ) );
- m_scrolledWindow3->SetMinSize( wxSize( -1,70 ) );
+ m_scrolledWindow3->SetMinSize( wxSize( -1,90 ) );
m_scrolledWindow3->SetMaxSize( wxSize( -1,100 ) );
wxBoxSizer* bSizer72;
@@ -1941,19 +1942,27 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_staticText68 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Jean-François Hartmann"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText68->Wrap( -1 );
- fgSizer9->Add( m_staticText68, 0, 0, 5 );
+ fgSizer9->Add( m_staticText68, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText69 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Français"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText69->Wrap( -1 );
- fgSizer9->Add( m_staticText69, 0, 0, 5 );
+ fgSizer9->Add( m_staticText69, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText70 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Tilt"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText70->Wrap( -1 );
- fgSizer9->Add( m_staticText70, 0, 0, 5 );
+ fgSizer9->Add( m_staticText70, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText71 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("日本語"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText71->Wrap( -1 );
- fgSizer9->Add( m_staticText71, 0, 0, 5 );
+ fgSizer9->Add( m_staticText71, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticText711 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("M.D. Vrakking"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText711->Wrap( -1 );
+ fgSizer9->Add( m_staticText711, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticText712 = new wxStaticText( m_scrolledWindow3, wxID_ANY, _("Nederlands"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText712->Wrap( -1 );
+ fgSizer9->Add( m_staticText712, 0, wxALIGN_CENTER_VERTICAL, 5 );
bSizer72->Add( fgSizer9, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 );
@@ -2108,12 +2117,12 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer25 = new wxBoxSizer( wxHORIZONTAL );
m_buttonContinue = new wxButton( this, wxID_OK, _("&Continue"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonContinue->SetDefault();
m_buttonContinue->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) );
bSizer25->Add( m_buttonContinue, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
m_buttonRetry = new wxButton( this, wxID_RETRY, _("&Retry"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonRetry->SetDefault();
m_buttonRetry->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) );
bSizer25->Add( m_buttonRetry, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
@@ -2271,9 +2280,21 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer52->Add( m_staticText45, 0, wxBOTTOM, 5 );
- m_staticText18 = new wxStaticText( m_panel13, wxID_ANY, _("1. Enter full file or directory names separated by ';' or a new line.\n2. Use wildcard characters '*' and '?'."), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText18->Wrap( -1 );
- bSizer52->Add( m_staticText18, 0, wxBOTTOM, 5 );
+ m_staticText83 = new wxStaticText( m_panel13, wxID_ANY, _("1. Enter full file or directory names separated by ';' or a new line."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText83->Wrap( -1 );
+ bSizer52->Add( m_staticText83, 0, 0, 5 );
+
+ m_staticText84 = new wxStaticText( m_panel13, wxID_ANY, _("2. Use wildcard characters '*' and '?'."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText84->Wrap( -1 );
+ bSizer52->Add( m_staticText84, 0, 0, 5 );
+
+ m_staticText85 = new wxStaticText( m_panel13, wxID_ANY, _("3. Exclude files directly on main grid via context menu."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText85->Wrap( -1 );
+ bSizer52->Add( m_staticText85, 0, 0, 5 );
+
+ m_staticText86 = new wxStaticText( m_panel13, wxID_ANY, _("4. Keep the number of entries small for best performance."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText86->Wrap( -1 );
+ bSizer52->Add( m_staticText86, 0, wxBOTTOM, 5 );
bSizer69->Add( bSizer52, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -2399,3 +2420,115 @@ FilterDlgGenerated::~FilterDlgGenerated()
m_button17->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnCancel ), NULL, this );
m_button10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FilterDlgGenerated::OnOK ), 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 )
+{
+ this->SetSizeHints( wxDefaultSize, wxDefaultSize );
+
+ wxBoxSizer* bSizer80;
+ bSizer80 = new wxBoxSizer( wxVERTICAL );
+
+ m_panel8 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER|wxTAB_TRAVERSAL );
+ m_panel8->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT ) );
+
+ wxBoxSizer* bSizer72;
+ bSizer72 = new wxBoxSizer( wxVERTICAL );
+
+
+ bSizer72->Add( 20, 0, 0, 0, 5 );
+
+ m_staticText56 = new wxStaticText( m_panel8, wxID_ANY, _("Adjust file times"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText56->Wrap( -1 );
+ m_staticText56->SetFont( wxFont( 16, 74, 90, 92, false, wxT("Tahoma") ) );
+
+ bSizer72->Add( m_staticText56, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+
+ bSizer72->Add( 20, 0, 0, 0, 5 );
+
+ m_panel8->SetSizer( bSizer72 );
+ m_panel8->Layout();
+ bSizer72->Fit( m_panel8 );
+ bSizer80->Add( m_panel8, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+
+ bSizer80->Add( 0, 5, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bSizer84;
+ bSizer84 = new wxBoxSizer( wxHORIZONTAL );
+
+
+ bSizer84->Add( 10, 0, 0, wxEXPAND, 5 );
+
+ m_staticTextHeader = new wxStaticText( this, wxID_ANY, _("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:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextHeader->Wrap( 400 );
+ m_staticTextHeader->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) );
+
+ bSizer84->Add( m_staticTextHeader, 0, wxALL, 5 );
+
+
+ bSizer84->Add( 10, 0, 0, wxEXPAND, 5 );
+
+ bSizer80->Add( bSizer84, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ m_hyperlink6 = new wxHyperlinkCtrl( this, wxID_ANY, _("http://www.codeproject.com/KB/datetime/dstbugs.aspx"), wxT("http://www.codeproject.com/KB/datetime/dstbugs.aspx"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ bSizer80->Add( m_hyperlink6, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+
+ bSizer80->Add( 0, 5, 0, wxEXPAND, 5 );
+
+ wxStaticBoxSizer* sbSizer24;
+ sbSizer24 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Select folder") ), wxHORIZONTAL );
+
+ m_textCtrlDirectory = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ sbSizer24->Add( m_textCtrlDirectory, 1, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+
+ m_dirPicker = new wxDirPickerCtrl( this, wxID_ANY, wxEmptyString, _("Select a folder"), wxDefaultPosition, wxDefaultSize, wxDIRP_DIR_MUST_EXIST );
+ sbSizer24->Add( m_dirPicker, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+
+ bSizer80->Add( sbSizer24, 0, wxEXPAND|wxALL, 5 );
+
+ wxStaticBoxSizer* sbSizer23;
+ sbSizer23 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Time shift in seconds") ), wxVERTICAL );
+
+ m_spinCtrlTimeShift = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -2100000000, 2100000000, 0 );
+ sbSizer23->Add( m_spinCtrlTimeShift, 0, wxRIGHT|wxLEFT, 5 );
+
+ bSizer80->Add( sbSizer23, 0, wxALL|wxEXPAND, 5 );
+
+ 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_ANY, _("Apply"), wxDefaultPosition, wxSize( -1,35 ), 0 );
+ m_buttonApply->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) );
+
+ bSizer83->Add( m_buttonApply, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ bSizer80->Add( bSizer83, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ this->SetSizer( bSizer80 );
+ this->Layout();
+ bSizer80->Fit( this );
+
+ // Connect Events
+ 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 );
+}
+
+ModifyFilesDlgGenerated::~ModifyFilesDlgGenerated()
+{
+ // Disconnect Events
+ 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 );
+}
diff --git a/ui/guiGenerated.h b/ui/guiGenerated.h
index 7df68fd7..81875ec6 100644
--- a/ui/guiGenerated.h
+++ b/ui/guiGenerated.h
@@ -43,6 +43,7 @@ class CustomGrid;
#include <wx/animate.h>
#include <wx/treectrl.h>
#include <wx/notebook.h>
+#include <wx/spinctrl.h>
///////////////////////////////////////////////////////////////////////////
@@ -59,9 +60,10 @@ protected:
wxMenu* m_menu1;
wxMenu* m_menu3;
wxMenu* m_menu31;
- wxMenuItem* m_menuItemEnglish;
wxMenuItem* m_menuItemGerman;
+ wxMenuItem* m_menuItemEnglish;
wxMenuItem* m_menuItemFrench;
+ wxMenuItem* m_menuItemDutch;
wxMenuItem* m_menuItemJapanese;
wxMenu* m_menu2;
wxBoxSizer* bSizer1;
@@ -134,15 +136,15 @@ protected:
{
event.Skip();
}
- virtual void OnMenuQuit( wxCommandEvent& event )
+ virtual void OnCompare( wxCommandEvent& event )
{
event.Skip();
}
- virtual void OnMenuExportFileList( wxCommandEvent& event )
+ virtual void OnSync( wxCommandEvent& event )
{
event.Skip();
}
- virtual void OnMenuLangEnglish( wxCommandEvent& event )
+ virtual void OnMenuQuit( wxCommandEvent& event )
{
event.Skip();
}
@@ -150,23 +152,35 @@ protected:
{
event.Skip();
}
+ virtual void OnMenuLangEnglish( wxCommandEvent& event )
+ {
+ event.Skip();
+ }
virtual void OnMenuLangFrench( wxCommandEvent& event )
{
event.Skip();
}
+ virtual void OnMenuLangDutch( wxCommandEvent& event )
+ {
+ event.Skip();
+ }
virtual void OnMenuLangJapanese( wxCommandEvent& event )
{
event.Skip();
}
+ virtual void OnMenuAdjustFileTimes( wxCommandEvent& event )
+ {
+ event.Skip();
+ }
virtual void OnMenuBatchJob( wxCommandEvent& event )
{
event.Skip();
}
- virtual void OnMenuAbout( wxCommandEvent& event )
+ virtual void OnMenuExportFileList( wxCommandEvent& event )
{
event.Skip();
}
- virtual void OnCompare( wxCommandEvent& event )
+ virtual void OnMenuAbout( wxCommandEvent& event )
{
event.Skip();
}
@@ -198,10 +212,6 @@ protected:
{
event.Skip();
}
- virtual void OnSync( wxCommandEvent& event )
- {
- event.Skip();
- }
virtual void OnWriteDirManually( wxCommandEvent& event )
{
event.Skip();
@@ -730,6 +740,8 @@ protected:
wxStaticText* m_staticText69;
wxStaticText* m_staticText70;
wxStaticText* m_staticText71;
+ wxStaticText* m_staticText711;
+ wxStaticText* m_staticText712;
wxStaticLine* m_staticline3;
wxStaticText* m_staticText131;
wxStaticBitmap* m_bitmap9;
@@ -862,7 +874,10 @@ protected:
wxPanel* m_panel13;
wxStaticLine* m_staticline10;
wxStaticText* m_staticText45;
- wxStaticText* m_staticText18;
+ wxStaticText* m_staticText83;
+ wxStaticText* m_staticText84;
+ wxStaticText* m_staticText85;
+ wxStaticText* m_staticText86;
wxStaticText* m_staticText181;
wxStaticText* m_staticText1811;
@@ -908,4 +923,57 @@ public:
};
+///////////////////////////////////////////////////////////////////////////////
+/// Class ModifyFilesDlgGenerated
+///////////////////////////////////////////////////////////////////////////////
+class ModifyFilesDlgGenerated : public wxDialog
+{
+private:
+
+protected:
+ wxPanel* m_panel8;
+
+ wxStaticText* m_staticText56;
+
+
+
+ wxStaticText* m_staticTextHeader;
+
+ wxHyperlinkCtrl* m_hyperlink6;
+
+ wxTextCtrl* m_textCtrlDirectory;
+ wxDirPickerCtrl* m_dirPicker;
+ wxSpinCtrl* m_spinCtrlTimeShift;
+ wxButton* m_button21;
+ wxButton* m_buttonApply;
+
+ // 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();
+ }
+
+
+public:
+ ModifyFilesDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+ ~ModifyFilesDlgGenerated();
+
+};
+
#endif //__guiGenerated__
bgstack15