diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:54:32 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:54:32 +0200 |
commit | cbb59ba3fb48fb87065469eaa1b4a34a18851b9e (patch) | |
tree | 6f43ab99e0f22a33fccb941ab0441d1bee38adf9 /library | |
parent | 1.11 (diff) | |
download | FreeFileSync-cbb59ba3fb48fb87065469eaa1b4a34a18851b9e.tar.gz FreeFileSync-cbb59ba3fb48fb87065469eaa1b4a34a18851b9e.tar.bz2 FreeFileSync-cbb59ba3fb48fb87065469eaa1b4a34a18851b9e.zip |
1.12
Diffstat (limited to 'library')
-rw-r--r-- | library/CustomGrid.cpp | 27 | ||||
-rw-r--r-- | library/CustomGrid.h | 2 | ||||
-rw-r--r-- | library/globalFunctions.cpp | 76 | ||||
-rw-r--r-- | library/globalFunctions.h | 49 | ||||
-rw-r--r-- | library/misc.cpp | 58 | ||||
-rw-r--r-- | library/misc.h | 9 | ||||
-rw-r--r-- | library/multithreading.cpp | 6 | ||||
-rw-r--r-- | library/multithreading.h | 52 | ||||
-rw-r--r-- | library/processXml.cpp | 427 | ||||
-rw-r--r-- | library/processXml.h | 115 | ||||
-rw-r--r-- | library/resources.cpp | 21 | ||||
-rw-r--r-- | library/resources.h | 19 | ||||
-rw-r--r-- | library/sorting.h | 274 | ||||
-rw-r--r-- | library/statusHandler.h | 76 | ||||
-rw-r--r-- | library/wxWidgets.h | 19 |
15 files changed, 916 insertions, 314 deletions
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 |