summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-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
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
bgstack15