summaryrefslogtreecommitdiff
path: root/library/process_xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/process_xml.cpp')
-rw-r--r--library/process_xml.cpp1646
1 files changed, 700 insertions, 946 deletions
diff --git a/library/process_xml.cpp b/library/process_xml.cpp
index 0e591116..1b5f6360 100644
--- a/library/process_xml.cpp
+++ b/library/process_xml.cpp
@@ -1,44 +1,30 @@
-// **************************************************************************
+// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
// **************************************************************************
//
#include "process_xml.h"
+#include <zenxml/zenxml.h>
#include "../shared/i18n.h"
#include "../shared/global_func.h"
#include "../shared/standard_paths.h"
#include "../shared/string_conv.h"
#include "../shared/file_handling.h"
+#include "../shared/file_io.h"
+#include "../shared/xml_base.h"
using namespace zen;
-using namespace xmlAccess; //functionally needed!!!
-
-
-XmlType xmlAccess::getXmlType(const wxString& filename) //throw()
-{
- try
- {
- TiXmlDocument doc;
- loadXmlDocument(filename, doc); //throw (XmlError)
- return getXmlType(doc);
- }
- catch (const XmlError&) {}
-
- return XML_TYPE_OTHER;
-}
+using namespace xmlAccess; //functionally needed for correct overload resolution!!!
-XmlType xmlAccess::getXmlType(const TiXmlDocument& doc) //throw()
+XmlType getXmlType(const zen::XmlDoc& doc) //throw()
{
- const TiXmlElement* root = doc.RootElement();
- if (root && root->ValueStr() == std::string("FreeFileSync"))
+ if (doc.root().getNameAs<std::string>() == "FreeFileSync")
{
- const char* cfgType = root->Attribute("XmlType");
- if (cfgType)
+ std::string type;
+ if (doc.root().getAttribute("XmlType", type))
{
- const std::string type(cfgType);
-
if (type == "GUI")
return XML_TYPE_GUI;
else if (type == "BATCH")
@@ -51,1288 +37,1056 @@ XmlType xmlAccess::getXmlType(const TiXmlDocument& doc) //throw()
}
-void xmlAccess::initXmlDocument(TiXmlDocument& doc, XmlType type) //throw()
+XmlType xmlAccess::getXmlType(const wxString& filename) //throw()
{
- TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); //delete won't be necessary later; ownership passed to TiXmlDocument!
- doc.LinkEndChild(decl);
+ XmlDoc doc;
+ try
+ {
+ std::string stream = loadStream(filename); //throw XmlFileError
+ parse(stream, doc); //throw XmlParsingError
+ }
+ catch (const zen::XmlError&) //catch XmlFileError, XmlParsingError
+ {
+ return XML_TYPE_OTHER;
+ }
+ return ::getXmlType(doc);
+}
- TiXmlElement* root = new TiXmlElement("FreeFileSync");
- doc.LinkEndChild(root);
+void setXmlType(XmlDoc& doc, XmlType type) //throw()
+{
switch (type)
{
case XML_TYPE_GUI:
- addXmlAttribute("XmlType", "GUI", doc.RootElement());
+ doc.root().setAttribute("XmlType", "GUI");
break;
case XML_TYPE_BATCH:
- addXmlAttribute("XmlType", "BATCH", doc.RootElement());
+ doc.root().setAttribute("XmlType", "BATCH");
break;
case XML_TYPE_GLOBAL:
- addXmlAttribute("XmlType", "GLOBAL", doc.RootElement());
+ doc.root().setAttribute("XmlType", "GLOBAL");
break;
case XML_TYPE_OTHER:
+ assert(false);
break;
}
}
+//################################################################################################################
-class FfsXmlErrorLogger : public xmlAccess::XmlErrorLogger
-{
-public:
- //read gui settings, all values retrieved are optional, so check for initial values! (== -1)
- void readConfig(const TiXmlElement* root, xmlAccess::XmlGuiConfig& outputCfg);
- //read batch settings, all values retrieved are optional
- void readConfig(const TiXmlElement* root, xmlAccess::XmlBatchConfig& outputCfg);
- //read global settings, valid for both GUI and batch mode, independent from configuration
- void readConfig(const TiXmlElement* root, xmlAccess::XmlGlobalSettings& outputCfg);
-
-private:
- //read alternate configuration (optional) => might point to NULL
- void readConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair);
- void readFilter(const TiXmlElement& parent, FilterConfig& output);
-
- //read basic FreefileSync settings (used by commandline and GUI)
- void readConfig(const TiXmlElement* root, MainConfiguration& mainCfg);
-};
-
-
-
-bool readXmlElement(const std::string& name, const TiXmlElement* parent, CompareVariant& output)
+wxString xmlAccess::getGlobalConfigFile()
{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "ByTimeAndSize")
- output = zen::CMP_BY_TIME_SIZE;
- else if (dummy == "ByContent")
- output = zen::CMP_BY_CONTENT;
- else
- return false;
-
- return true;
- }
- else
- return false;
+ return zen::getConfigDir() + wxT("GlobalSettings.xml");
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent, SyncDirection& output)
+void xmlAccess::OptionalDialogs::resetDialogs()
{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "left")
- output = SYNC_DIR_LEFT;
- else if (dummy == "right")
- output = SYNC_DIR_RIGHT;
- else //treat all other input as "none"
- output = SYNC_DIR_NONE;
-
- return true;
- }
- else
- return false;
+ warningDependentFolders = true;
+ warningMultiFolderWriteAccess = true;
+ warningSignificantDifference = true;
+ warningNotEnoughDiskSpace = true;
+ warningUnresolvedConflicts = true;
+ warningSyncDatabase = true;
+ popupOnConfigChange = true;
+ showSummaryBeforeSync = true;
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent, xmlAccess::OnError& output)
+xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchConfig& batchCfg)
{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "Ignore")
- output = xmlAccess::ON_ERROR_IGNORE;
- else if (dummy == "Exit")
- output = xmlAccess::ON_ERROR_EXIT;
- else //treat all other input as popup
- output = xmlAccess::ON_ERROR_POPUP;
-
- return true;
- }
- else
- return false;
+ XmlGuiConfig output;
+ output.mainCfg = batchCfg.mainCfg;
+ return output;
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , OnGuiError& output)
+xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg)
{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "Popup")
- output = ON_GUIERROR_POPUP;
- else if (dummy == "Ignore")
- output = ON_GUIERROR_IGNORE;
- else
- return false;
-
- return true;
- }
- return false;
-}
-
+ XmlBatchConfig output;
+ output.mainCfg = guiCfg.mainCfg;
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::DeletionPolicy& output)
-{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
+ switch (guiCfg.handleError)
{
- if (dummy == "DeletePermanently")
- output = zen::DELETE_PERMANENTLY;
- else if (dummy == "MoveToRecycleBin")
- output = zen::MOVE_TO_RECYCLE_BIN;
- else if (dummy == "MoveToCustomDirectory")
- output = zen::MOVE_TO_CUSTOM_DIRECTORY;
- else
- return false;
-
- return true;
+ case ON_GUIERROR_POPUP:
+ output.handleError = xmlAccess::ON_ERROR_POPUP;
+ break;
+ case ON_GUIERROR_IGNORE:
+ output.handleError = xmlAccess::ON_ERROR_IGNORE;
+ break;
}
- return false;
-}
-
-
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::SymLinkHandling& output)
-{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "Ignore")
- output = zen::SYMLINK_IGNORE;
- else if (dummy == "UseDirectly")
- output = zen::SYMLINK_USE_DIRECTLY;
- else if (dummy == "FollowLink")
- output = zen::SYMLINK_FOLLOW_LINK;
- else
- return false;
- return true;
- }
- return false;
+ return output;
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::UnitTime& output)
+xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filenames) //throw ()
{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
- {
- if (dummy == "Inactive")
- output = zen::UTIME_NONE;
- else if (dummy == "Second")
- output = zen::UTIME_SEC;
- else if (dummy == "Minute")
- output = zen::UTIME_MIN;
- else if (dummy == "Hour")
- output = zen::UTIME_HOUR;
- else if (dummy == "Day")
- output = zen::UTIME_DAY;
- else
- return false;
-
- return true;
- }
- return false;
-}
-
+ bool guiCfgExists = false;
+ bool batchCfgExists = false;
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::UnitSize& output)
-{
- std::string dummy;
- if (xmlAccess::readXmlElement(name, parent, dummy))
+ for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
{
- if (dummy == "Inactive")
- output = zen::USIZE_NONE;
- else if (dummy == "Byte")
- output = zen::USIZE_BYTE;
- else if (dummy == "KB")
- output = zen::USIZE_KB;
- else if (dummy == "MB")
- output = zen::USIZE_MB;
- else
- return false;
-
- return true;
- }
- return false;
-}
+ switch (xmlAccess::getXmlType(*i)) //throw()
+ {
+ case XML_TYPE_GUI:
+ guiCfgExists = true;
+ break;
+ case XML_TYPE_BATCH:
+ batchCfgExists = true;
+ break;
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::SyncConfig::Variant& output)
-{
- std::string dummy;
- if (!xmlAccess::readXmlElement(name, parent, dummy))
- return false;
+ case XML_TYPE_GLOBAL:
+ case XML_TYPE_OTHER:
+ return MERGE_OTHER;
+ }
+ }
- if (dummy == "Automatic")
- output = SyncConfig::AUTOMATIC;
- else if (dummy == "Mirror")
- output = SyncConfig::MIRROR;
- else if (dummy == "Update")
- output = SyncConfig::UPDATE;
- else if (dummy == "Custom")
- output = SyncConfig::CUSTOM;
+ if (guiCfgExists && batchCfgExists)
+ return MERGE_GUI_BATCH;
+ else if (guiCfgExists && !batchCfgExists)
+ return MERGE_GUI;
+ else if (!guiCfgExists && batchCfgExists)
+ return MERGE_BATCH;
else
- return false;
-
- return true;
+ return MERGE_OTHER;
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent, Zstring& output)
+namespace
{
- wxString dummy;
- if (!xmlAccess::readXmlElement(name, parent, dummy))
- return false;
-
- output = wxToZ(dummy);
- return true;
-}
-
-
-bool readXmlAttribute(const std::string& name, const TiXmlElement* node, xmlAccess::ColumnTypes& output)
+template <class XmlCfg>
+XmlCfg loadCfgImpl(const wxString& filename, std::unique_ptr<xmlAccess::FfsXmlError>& exeption) //throw (xmlAccess::FfsXmlError)
{
- int dummy = 0;
- if (xmlAccess::readXmlAttribute(name, node, dummy))
+ XmlCfg cfg;
+ try
{
- output = static_cast<xmlAccess::ColumnTypes>(dummy);
- return true;
+ xmlAccess::readConfig(filename, cfg); //throw (xmlAccess::FfsXmlError);
}
- else
- return false;
-}
-
-
-void FfsXmlErrorLogger::readFilter(const TiXmlElement& parent, FilterConfig& output)
-{
- //read filter settings
- readXmlElementLogging("Include", &parent, output.includeFilter);
- readXmlElementLogging("Exclude", &parent, output.excludeFilter);
-
- //migration "strategy": no error checking on these... :P
-
- readXmlElementLogging("TimeSpan", &parent, output.timeSpan);
- readXmlElementLogging("UnitTimeSpan", &parent, output.unitTimeSpan);
-
- readXmlElementLogging("SizeMin", &parent, output.sizeMin);
- readXmlElementLogging("UnitSizeMin", &parent, output.unitSizeMin);
-
- readXmlElementLogging("SizeMax", &parent, output.sizeMax);
- readXmlElementLogging("UnitSizeMax", &parent, output.unitSizeMax);
-}
-
-
-//################################################################################################################
-void FfsXmlErrorLogger::readConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair)
-{
- //read folder pairs
- readXmlElementLogging("Left", &folderPair, enhPair.leftDirectory);
- readXmlElementLogging("Right", &folderPair, enhPair.rightDirectory);
-
-
- //###########################################################
- //alternate sync configuration
- const TiXmlElement* xmlAltSyncCfg = TiXmlHandleConst(&folderPair).FirstChild("AlternateSyncConfig").ToElement();
- if (xmlAltSyncCfg)
+ catch (const xmlAccess::FfsXmlError& e)
{
- AlternateSyncConfig* altSyncCfg = new AlternateSyncConfig;
- enhPair.altSyncConfig.reset(altSyncCfg);
-
- const TiXmlElement* xmlSyncDirections = TiXmlHandleConst(xmlAltSyncCfg).FirstChild("CustomDirections").ToElement();
-
- //read sync configuration
- readXmlElementLogging("Variant", xmlAltSyncCfg, altSyncCfg->syncConfiguration.var);
-
- readXmlElementLogging("LeftOnly", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.exLeftSideOnly);
- readXmlElementLogging("RightOnly", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.exRightSideOnly);
- readXmlElementLogging("LeftNewer", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.leftNewer);
- readXmlElementLogging("RightNewer", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.rightNewer);
- readXmlElementLogging("Different", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.different);
- readXmlElementLogging("Conflict", xmlSyncDirections, altSyncCfg->syncConfiguration.custom.conflict);
-
- readXmlElementLogging("DeletionPolicy", xmlAltSyncCfg, altSyncCfg->handleDeletion);
- readXmlElementLogging("CustomDeletionFolder", xmlAltSyncCfg, altSyncCfg->customDeletionDirectory);
+ if (e.getSeverity() == xmlAccess::FfsXmlError::FATAL)
+ throw;
+ else
+ exeption.reset(new xmlAccess::FfsXmlError(e));
}
-
- //###########################################################
- //alternate filter configuration
- const TiXmlElement* filterCfg = TiXmlHandleConst(&folderPair).FirstChild("LocalFilter").ToElement();
- if (filterCfg)
- readFilter(*filterCfg, enhPair.localFilter);
+ return cfg;
}
-void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, MainConfiguration& mainCfg)
+template <class XmlCfg>
+void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config) //throw (xmlAccess::FfsXmlError)
{
- TiXmlHandleConst hRoot(root); //custom const handle: TiXml API seems broken in this regard
-
- //###########################################################
- const TiXmlElement* xmlMainConfig = hRoot.FirstChild("MainConfig").ToElement();
-
- const TiXmlElement* cmpSettings = hRoot.FirstChild("MainConfig").FirstChild("Comparison").ToElement();
-
- //read compare variant
- readXmlElementLogging("Variant", cmpSettings, mainCfg.compareVar);
-
- //include symbolic links at all?
- readXmlElementLogging("HandleSymlinks", cmpSettings, mainCfg.handleSymlinks);
-
- //###########################################################
- const TiXmlElement* xmlSyncCfg = hRoot.FirstChild("MainConfig").FirstChild("SyncConfig").ToElement();
- const TiXmlElement* syncDirections = TiXmlHandleConst(xmlSyncCfg).FirstChild("CustomDirections").ToElement();
-
- //read sync configuration
- readXmlElementLogging("Variant", xmlSyncCfg, mainCfg.syncConfiguration.var);
-
- readXmlElementLogging("LeftOnly", syncDirections, mainCfg.syncConfiguration.custom.exLeftSideOnly);
- readXmlElementLogging("RightOnly", syncDirections, mainCfg.syncConfiguration.custom.exRightSideOnly);
- readXmlElementLogging("LeftNewer", syncDirections, mainCfg.syncConfiguration.custom.leftNewer);
- readXmlElementLogging("RightNewer", syncDirections, mainCfg.syncConfiguration.custom.rightNewer);
- readXmlElementLogging("Different", syncDirections, mainCfg.syncConfiguration.custom.different);
- readXmlElementLogging("Conflict", syncDirections, mainCfg.syncConfiguration.custom.conflict);
-
- //###########################################################
- //misc
- readXmlElementLogging("DeletionPolicy", xmlSyncCfg, mainCfg.handleDeletion);
- readXmlElementLogging("CustomDeletionFolder", xmlSyncCfg, mainCfg.customDeletionDirectory);
- //###########################################################
- const TiXmlElement* filter = TiXmlHandleConst(xmlMainConfig).FirstChild("GlobalFilter").ToElement();
+ using namespace xmlAccess;
- //read filter settings
- if (filter)
- readFilter(*filter, mainCfg.globalFilter);
- else
- logError("GlobalFilter");
+ assert(!filenames.empty());
+ if (filenames.empty())
+ return;
- //###########################################################
- const TiXmlElement* pairs = hRoot.FirstChild("MainConfig").FirstChild("FolderPairs").FirstChild("Pair").ToElement();
+ std::vector<zen::MainConfiguration> mainCfgs;
+ std::unique_ptr<FfsXmlError> savedException;
- //read all folder pairs
- mainCfg.additionalPairs.clear();
- bool firstLoop = true;
- while (pairs)
+ for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
{
- FolderPairEnh newPair;
- readConfig(*pairs, newPair);
-
- if (firstLoop) //read first folder pair
+ switch (getXmlType(*i))
{
- firstLoop = false;
- mainCfg.firstPair = newPair;
- }
- else //read additional folder pairs
- mainCfg.additionalPairs.push_back(newPair);
+ case XML_TYPE_GUI:
+ mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(*i, savedException).mainCfg); //throw (xmlAccess::FfsXmlError)
+ break;
+
+ case XML_TYPE_BATCH:
+ mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(*i, savedException).mainCfg); //throw (xmlAccess::FfsXmlError)
+ break;
- pairs = pairs->NextSiblingElement();
+ case XML_TYPE_GLOBAL:
+ case XML_TYPE_OTHER:
+ break;
+ }
}
-}
+ if (mainCfgs.empty())
+ throw FfsXmlError(_("Invalid FreeFileSync config file!"));
-void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlGuiConfig& outputCfg)
-{
- //read main config
- readConfig(root, outputCfg.mainCfg);
+ try //...to init all non-"mainCfg" settings with first config file
+ {
+ xmlAccess::readConfig(filenames[0], config); //throw (xmlAccess::FfsXmlError);
+ }
+ catch (...) {}
- //read GUI specific config data
- const TiXmlElement* guiConfig = TiXmlHandleConst(root).FirstChild("GuiConfig").ToElement();
+ config.mainCfg = merge(mainCfgs);
- readXmlElementLogging("HideFiltered", guiConfig, outputCfg.hideFilteredElements);
- readXmlElementLogging("HandleError", guiConfig, outputCfg.handleError);
- readXmlElementLogging("SyncPreviewActive", guiConfig, outputCfg.syncPreviewEnabled);
+ if (savedException.get()) //"re-throw" exception
+ throw* savedException;
+}
}
-void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlBatchConfig& outputCfg)
+void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config) //throw (xmlAccess::FfsXmlError)
{
- //read main config
- readConfig(root, outputCfg.mainCfg);
-
- //read batch specific config
- const TiXmlElement* batchConfig = TiXmlHandleConst(root).FirstChild("BatchConfig").ToElement();
-
- readXmlElementLogging("Silent", batchConfig, outputCfg.silent);
- readXmlElementLogging("LogfileDirectory", batchConfig, outputCfg.logFileDirectory);
- readXmlElementLogging("LogfileCountMax", batchConfig, outputCfg.logFileCountMax);
- readXmlElementLogging("HandleError", batchConfig, outputCfg.handleError);
+ mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
}
-void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlGlobalSettings& outputCfg)
+void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config) //throw (xmlAccess::FfsXmlError);
{
- //read global settings
- const TiXmlElement* global = TiXmlHandleConst(root).FirstChild("Shared").ToElement();
-
- //try to read program language setting
- readXmlElementLogging("Language", global, outputCfg.programLanguage);
-
- //copy locked files using VSS
- readXmlElementLogging("CopyLockedFiles", global, outputCfg.copyLockedFiles);
-
- //file permissions
- readXmlElementLogging("CopyFilePermissions", global, outputCfg.copyFilePermissions);
-
- //verify file copying
- readXmlElementLogging("VerifyCopiedFiles", global, outputCfg.verifyFileCopy);
-
- //max. allowed file time deviation
- readXmlElementLogging("FileTimeTolerance", global, outputCfg.fileTimeTolerance);
-
-
- const TiXmlElement* optionalDialogs = TiXmlHandleConst(root).FirstChild("Shared").FirstChild("ShowOptionalDialogs").ToElement();
-
- //folder dependency check
- readXmlElementLogging("CheckForDependentFolders", optionalDialogs, outputCfg.optDialogs.warningDependentFolders);
-
- //check for multi write access for directory as part of multiple pairs
- readXmlElementLogging("CheckForMultipleWriteAccess", optionalDialogs, outputCfg.optDialogs.warningMultiFolderWriteAccess);
-
- //significant difference check
- readXmlElementLogging("CheckForSignificantDifference", optionalDialogs, outputCfg.optDialogs.warningSignificantDifference);
- //check free disk space
- readXmlElementLogging("CheckForFreeDiskSpace", optionalDialogs, outputCfg.optDialogs.warningNotEnoughDiskSpace);
- //check for unresolved conflicts
- readXmlElementLogging("CheckForUnresolvedConflicts", optionalDialogs, outputCfg.optDialogs.warningUnresolvedConflicts);
-
- readXmlElementLogging("NotifyDatabaseError", optionalDialogs, outputCfg.optDialogs.warningSyncDatabase);
-
- readXmlElementLogging("PopupOnConfigChange", optionalDialogs, outputCfg.optDialogs.popupOnConfigChange);
-
- readXmlElementLogging("SummaryBeforeSync", optionalDialogs, outputCfg.optDialogs.showSummaryBeforeSync);
-
-
- //gui specific global settings (optional)
- const TiXmlElement* gui = TiXmlHandleConst(root).FirstChild("Gui").ToElement();
- const TiXmlElement* mainWindow = TiXmlHandleConst(gui).FirstChild("Windows").FirstChild("Main").ToElement();
-
- //read application window size and position
- readXmlElementLogging("Width", mainWindow, outputCfg.gui.widthNotMaximized);
- readXmlElementLogging("Height", mainWindow, outputCfg.gui.heightNotMaximized);
- readXmlElementLogging("PosX", mainWindow, outputCfg.gui.posXNotMaximized);
- readXmlElementLogging("PosY", mainWindow, outputCfg.gui.posYNotMaximized);
- readXmlElementLogging("Maximized", mainWindow, outputCfg.gui.isMaximized);
-
- readXmlElementLogging("ManualDeletionOnBothSides", mainWindow, outputCfg.gui.deleteOnBothSides);
- readXmlElementLogging("ManualDeletionUseRecycler", mainWindow, outputCfg.gui.useRecyclerForManualDeletion);
-
- readXmlElementLogging("RespectCaseOnSearch", mainWindow, outputCfg.gui.textSearchRespectCase);
-
- size_t folderPairMax = 0;
- readXmlElementLogging("FolderPairsMax", mainWindow, folderPairMax);
- if (folderPairMax != 0) //if reading fails, leave at default
- outputCfg.gui.addFolderPairCountMax = std::max(static_cast<size_t>(2), folderPairMax) - 1; //map folderPairMax to additionalFolderPairMax
-
- //###########################################################
- //read column attributes
- readXmlAttributeLogging("AutoAdjust", TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").ToElement(), outputCfg.gui.autoAdjustColumnsLeft);
- readXmlAttributeLogging("ShowFileIcons", TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").ToElement(), outputCfg.gui.showFileIconsLeft);
-
- const TiXmlElement* leftColumn = TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement();
- size_t colPos = 0;
- while (leftColumn)
- {
- ColumnAttrib newAttrib;
- newAttrib.position = colPos++;
- readXmlAttributeLogging("Type", leftColumn, newAttrib.type);
- readXmlAttributeLogging("Visible", leftColumn, newAttrib.visible);
- readXmlAttributeLogging("Width", leftColumn, newAttrib.width);
- outputCfg.gui.columnAttribLeft.push_back(newAttrib);
-
- leftColumn = leftColumn->NextSiblingElement();
- }
-
- readXmlAttributeLogging("AutoAdjust", TiXmlHandleConst(mainWindow).FirstChild("RightColumns").ToElement(), outputCfg.gui.autoAdjustColumnsRight);
- readXmlAttributeLogging("ShowFileIcons", TiXmlHandleConst(mainWindow).FirstChild("RightColumns").ToElement(), outputCfg.gui.showFileIconsRight);
-
- const TiXmlElement* rightColumn = TiXmlHandleConst(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement();
- colPos = 0;
- while (rightColumn)
- {
- ColumnAttrib newAttrib;
- newAttrib.position = colPos++;
- readXmlAttributeLogging("Type", rightColumn, newAttrib.type);
- readXmlAttributeLogging("Visible", rightColumn, newAttrib.visible);
- readXmlAttributeLogging("Width", rightColumn, newAttrib.width);
- outputCfg.gui.columnAttribRight.push_back(newAttrib);
-
- rightColumn = rightColumn->NextSiblingElement();
- }
-
- readXmlElementLogging("FolderHistoryLeft", mainWindow, outputCfg.gui.folderHistoryLeft);
- readXmlElementLogging("FolderHistoryRight", mainWindow, outputCfg.gui.folderHistoryRight);
- readXmlElementLogging("MaximumHistorySize", mainWindow, outputCfg.gui.folderHistMax);
-
- readXmlElementLogging("Perspective", mainWindow, outputCfg.gui.guiPerspectiveLast);
-
- //external applications
- const TiXmlElement* extApps = TiXmlHandleConst(gui).FirstChild("ExternalApplications").FirstChild("Commandline").ToElement();
- if (extApps)
- {
- outputCfg.gui.externelApplications.clear();
- while (extApps)
- {
- wxString description;
- wxString cmdLine;
-
- readXmlAttributeLogging("Description", extApps, description);
- const char* text = extApps->GetText();
- if (text) cmdLine = wxString::FromUTF8(text); //read commandline
- outputCfg.gui.externelApplications.push_back(std::make_pair(description, cmdLine));
-
- extApps = extApps->NextSiblingElement();
- }
- }
- //load config file history
- const TiXmlElement* cfgHistory = TiXmlHandleConst(gui).FirstChild("ConfigHistory").ToElement();
-
- //load config history elements
- readXmlAttributeLogging("LastUsed", cfgHistory, outputCfg.gui.lastUsedConfigFile);
- readXmlElementLogging("File", cfgHistory, outputCfg.gui.cfgFileHistory);
-
- //last update check
- readXmlElementLogging("LastUpdateCheck", gui, outputCfg.gui.lastUpdateCheck);
-
-
- //batch specific global settings
- //const TiXmlElement* batch = TiXmlHandleConst(root).FirstChild("Batch").ToElement();
+ mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
}
-void addXmlElement(const std::string& name, const CompareVariant variant, TiXmlElement* parent)
+namespace zen
+{
+template <> inline
+void writeText(const CompareVariant& value, std::string& output)
{
- switch (variant)
+ switch (value)
{
case zen::CMP_BY_TIME_SIZE:
- xmlAccess::addXmlElement(name, std::string("ByTimeAndSize"), parent);
+ output = "ByTimeAndSize";
break;
case zen::CMP_BY_CONTENT:
- xmlAccess::addXmlElement(name, std::string("ByContent"), parent);
+ output = "ByContent";
break;
}
}
+template <> inline
+bool readText(const std::string& input, CompareVariant& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "ByTimeAndSize")
+ value = zen::CMP_BY_TIME_SIZE;
+ else if (tmp == "ByContent")
+ value = zen::CMP_BY_CONTENT;
+ else
+ return false;
+ return true;
+}
-void addXmlElement(const std::string& name, const SyncDirection value, TiXmlElement* parent)
+
+template <> inline
+void writeText(const SyncDirection& value, std::string& output)
{
switch (value)
{
case SYNC_DIR_LEFT:
- xmlAccess::addXmlElement(name, std::string("left"), parent);
+ output = "left";
break;
case SYNC_DIR_RIGHT:
- xmlAccess::addXmlElement(name, std::string("right"), parent);
+ output = "right";
break;
case SYNC_DIR_NONE:
- xmlAccess::addXmlElement(name, std::string("none"), parent);
+ output = "none";
break;
}
}
+template <> inline
+bool readText(const std::string& input, SyncDirection& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "left")
+ value = SYNC_DIR_LEFT;
+ else if (tmp == "right")
+ value = SYNC_DIR_RIGHT;
+ else if (tmp == "none")
+ value = SYNC_DIR_NONE;
+ else
+ return false;
+ return true;
+}
+
-void addXmlElement(const std::string& name, const xmlAccess::OnError value, TiXmlElement* parent)
+template <> inline
+void writeText(const OnError& value, std::string& output)
{
switch (value)
{
- case xmlAccess::ON_ERROR_IGNORE:
- xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
+ case ON_ERROR_IGNORE:
+ output = "Ignore";
break;
- case xmlAccess::ON_ERROR_EXIT:
- xmlAccess::addXmlElement(name, std::string("Exit"), parent);
+ case ON_ERROR_EXIT:
+ output = "Exit";
break;
- case xmlAccess::ON_ERROR_POPUP:
- xmlAccess::addXmlElement(name, std::string("Popup"), parent);
+ case ON_ERROR_POPUP:
+ output = "Popup";
break;
}
}
+template <> inline
+bool readText(const std::string& input, OnError& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Ignore")
+ value = ON_ERROR_IGNORE;
+ else if (tmp == "Exit")
+ value = ON_ERROR_EXIT;
+ else if (tmp == "Popup")
+ value = ON_ERROR_POPUP;
+ else
+ return false;
+ return true;
+}
+
-void addXmlElement(const std::string& name, const OnGuiError value, TiXmlElement* parent)
+template <> inline
+void writeText(const OnGuiError& value, std::string& output)
{
switch (value)
{
case ON_GUIERROR_IGNORE:
- xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
+ output = "Ignore";
break;
case ON_GUIERROR_POPUP:
- xmlAccess::addXmlElement(name, std::string("Popup"), parent);
+ output = "Popup";
break;
}
}
+template <> inline
+bool readText(const std::string& input, OnGuiError& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Ignore")
+ value = ON_GUIERROR_IGNORE;
+ else if (tmp == "Popup")
+ value = ON_GUIERROR_POPUP;
+ else
+ return false;
+ return true;
+}
-void addXmlElement(const std::string& name, const zen::DeletionPolicy value, TiXmlElement* parent)
+
+template <> inline
+void writeText(const DeletionPolicy& value, std::string& output)
{
switch (value)
{
- case zen::DELETE_PERMANENTLY:
- xmlAccess::addXmlElement(name, std::string("DeletePermanently"), parent);
+ case DELETE_PERMANENTLY:
+ output = "DeletePermanently";
break;
- case zen::MOVE_TO_RECYCLE_BIN:
- xmlAccess::addXmlElement(name, std::string("MoveToRecycleBin"), parent);
+ case MOVE_TO_RECYCLE_BIN:
+ output = "MoveToRecycleBin";
break;
- case zen::MOVE_TO_CUSTOM_DIRECTORY:
- xmlAccess::addXmlElement(name, std::string("MoveToCustomDirectory"), parent);
+ case MOVE_TO_CUSTOM_DIRECTORY:
+ output = "MoveToCustomDirectory";
break;
}
}
+template <> inline
+bool readText(const std::string& input, DeletionPolicy& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "DeletePermanently")
+ value = DELETE_PERMANENTLY;
+ else if (tmp == "MoveToRecycleBin")
+ value = MOVE_TO_RECYCLE_BIN;
+ else if (tmp == "MoveToCustomDirectory")
+ value = MOVE_TO_CUSTOM_DIRECTORY;
+ else
+ return false;
+ return true;
+}
+
-void addXmlElement(const std::string& name, const zen::SymLinkHandling value, TiXmlElement* parent)
+template <> inline
+void writeText(const SymLinkHandling& value, std::string& output)
{
switch (value)
{
- case zen::SYMLINK_IGNORE:
- xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
+ case SYMLINK_IGNORE:
+ output = "Ignore";
break;
- case zen::SYMLINK_USE_DIRECTLY:
- xmlAccess::addXmlElement(name, std::string("UseDirectly"), parent);
+ case SYMLINK_USE_DIRECTLY:
+ output = "UseDirectly";
break;
- case zen::SYMLINK_FOLLOW_LINK:
- xmlAccess::addXmlElement(name, std::string("FollowLink"), parent);
+ case SYMLINK_FOLLOW_LINK:
+ output = "FollowLink";
break;
}
}
+template <> inline
+bool readText(const std::string& input, SymLinkHandling& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Ignore")
+ value = SYMLINK_IGNORE;
+ else if (tmp == "UseDirectly")
+ value = SYMLINK_USE_DIRECTLY;
+ else if (tmp == "FollowLink")
+ value = SYMLINK_FOLLOW_LINK;
+ else
+ return false;
+ return true;
+}
+
-void addXmlElement(const std::string& name, const zen::UnitTime value, TiXmlElement* parent)
+template <> inline
+void writeText(const UnitTime& value, std::string& output)
{
switch (value)
{
- case zen::UTIME_NONE:
- xmlAccess::addXmlElement(name, std::string("Inactive"), parent);
+ case UTIME_NONE:
+ output = "Inactive";
break;
- case zen::UTIME_SEC:
- xmlAccess::addXmlElement(name, std::string("Second"), parent);
+ case UTIME_SEC:
+ output = "Second";
break;
- case zen::UTIME_MIN:
- xmlAccess::addXmlElement(name, std::string("Minute"), parent);
+ case UTIME_MIN:
+ output = "Minute";
break;
- case zen::UTIME_HOUR:
- xmlAccess::addXmlElement(name, std::string("Hour"), parent);
+ case UTIME_HOUR:
+ output = "Hour";
break;
- case zen::UTIME_DAY:
- xmlAccess::addXmlElement(name, std::string("Day"), parent);
+ case UTIME_DAY:
+ output = "Day";
break;
}
}
+template <> inline
+bool readText(const std::string& input, UnitTime& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Inactive")
+ value = UTIME_NONE;
+ else if (tmp == "Second")
+ value = UTIME_SEC;
+ else if (tmp == "Minute")
+ value = UTIME_MIN;
+ else if (tmp == "Hour")
+ value = UTIME_HOUR;
+ else if (tmp == "Day")
+ value = UTIME_DAY;
+ else
+ return false;
+ return true;
+}
+
+
+template <> inline
+void writeText(const ColumnTypes& value, std::string& output)
+{
+ output = toString<std::string>(value);
+}
-void addXmlElement(const std::string& name, zen::UnitSize value, TiXmlElement* parent)
+template <> inline
+bool readText(const std::string& input, ColumnTypes& value)
+{
+ value = static_cast<ColumnTypes>(toNumber<int>(input));
+ return true;
+}
+
+
+template <> inline
+void writeText(const UnitSize& value, std::string& output)
{
switch (value)
{
- case zen::USIZE_NONE:
- xmlAccess::addXmlElement(name, std::string("Inactive"), parent);
+ case USIZE_NONE:
+ output = "Inactive";
break;
- case zen::USIZE_BYTE:
- xmlAccess::addXmlElement(name, std::string("Byte"), parent);
+ case USIZE_BYTE:
+ output = "Byte";
break;
- case zen::USIZE_KB:
- xmlAccess::addXmlElement(name, std::string("KB"), parent);
+ case USIZE_KB:
+ output = "KB";
break;
- case zen::USIZE_MB:
- xmlAccess::addXmlElement(name, std::string("MB"), parent);
+ case USIZE_MB:
+ output = "MB";
break;
}
}
+template <> inline
+bool readText(const std::string& input, UnitSize& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Inactive")
+ value = USIZE_NONE;
+ else if (tmp == "Byte")
+ value = USIZE_BYTE;
+ else if (tmp == "KB")
+ value = USIZE_KB;
+ else if (tmp == "MB")
+ value = USIZE_MB;
+ else
+ return false;
+ return true;
+}
+
-void addXmlElement(const std::string& name, SyncConfig::Variant value, TiXmlElement* parent)
+template <> inline
+void writeText(const SyncConfig::Variant& value, std::string& output)
{
switch (value)
{
case SyncConfig::AUTOMATIC:
- xmlAccess::addXmlElement(name, std::string("Automatic"), parent);
+ output = "Automatic";
break;
case SyncConfig::MIRROR:
- xmlAccess::addXmlElement(name, std::string("Mirror"), parent);
+ output = "Mirror";
break;
case SyncConfig::UPDATE:
- xmlAccess::addXmlElement(name, std::string("Update"), parent);
+ output = "Update";
break;
case SyncConfig::CUSTOM:
- xmlAccess::addXmlElement(name, std::string("Custom"), parent);
+ output = "Custom";
break;
}
}
-
-void addXmlElement(const std::string& name, const Zstring& value, TiXmlElement* parent)
+template <> inline
+bool readText(const std::string& input, SyncConfig::Variant& value)
{
- xmlAccess::addXmlElement(name, wxString(zToWx(value)), parent);
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Automatic")
+ value = SyncConfig::AUTOMATIC;
+ else if (tmp == "Mirror")
+ value = SyncConfig::MIRROR;
+ else if (tmp == "Update")
+ value = SyncConfig::UPDATE;
+ else if (tmp == "Custom")
+ value = SyncConfig::CUSTOM;
+ else
+ return false;
+ return true;
}
-void addXmlAttribute(const std::string& name, const xmlAccess::ColumnTypes value, TiXmlElement* node)
+template <> inline
+bool readValue(const XmlElement& input, ColumnAttrib& value)
{
- xmlAccess::addXmlAttribute(name, static_cast<int>(value), node);
+ XmlIn in(input);
+ bool rv1 = in.attribute("Type", value.type);
+ bool rv2 = in.attribute("Visible", value.visible);
+ bool rv3 = in.attribute("Width", value.width);
+ value.position = 0;
+ return rv1 && rv2 && rv3;
}
-
-void writeFilter(const FilterConfig& input, TiXmlElement& parent)
+template <> inline
+void writeValue(const ColumnAttrib& value, XmlElement& output)
{
- addXmlElement("Include", input.includeFilter, &parent);
- addXmlElement("Exclude", input.excludeFilter, &parent);
-
- addXmlElement("TimeSpan", input.timeSpan, &parent);
- addXmlElement("UnitTimeSpan", input.unitTimeSpan, &parent);
+ XmlOut out(output);
+ out.attribute("Type", value.type);
+ out.attribute("Visible", value.visible);
+ out.attribute("Width", value.width);
+}
+}
- addXmlElement("SizeMin", input.sizeMin, &parent);
- addXmlElement("UnitSizeMin", input.unitSizeMin, &parent);
- addXmlElement("SizeMax", input.sizeMax, &parent);
- addXmlElement("UnitSizeMax", input.unitSizeMax, &parent);
+namespace
+{
+void readConfig(const XmlIn& in, SyncConfig& syncCfg)
+{
+ in["Variant"](syncCfg.var);
+
+ XmlIn inCustDir = in["CustomDirections"];
+ inCustDir["LeftOnly" ](syncCfg.custom.exLeftSideOnly);
+ inCustDir["RightOnly" ](syncCfg.custom.exRightSideOnly);
+ inCustDir["LeftNewer" ](syncCfg.custom.leftNewer);
+ inCustDir["RightNewer"](syncCfg.custom.rightNewer);
+ inCustDir["Different" ](syncCfg.custom.different);
+ inCustDir["Conflict" ](syncCfg.custom.conflict);
}
-void writeXmlLocalConfig(const FolderPairEnh& enhPair, TiXmlElement& parent)
+void readConfig(const XmlIn& in, FilterConfig& filter)
{
- //write folder pairs
- TiXmlElement* newfolderPair = new TiXmlElement("Pair");
- parent.LinkEndChild(newfolderPair);
+ in["Include"](filter.includeFilter);
+ in["Exclude"](filter.excludeFilter);
- addXmlElement("Left", enhPair.leftDirectory, newfolderPair);
- addXmlElement("Right", enhPair.rightDirectory, newfolderPair);
+ in["TimeSpan" ](filter.timeSpan);
+ in["UnitTimeSpan"](filter.unitTimeSpan);
+ in["SizeMin" ](filter.sizeMin);
+ in["UnitSizeMin"](filter.unitSizeMin);
- //alternate sync configuration
- const AlternateSyncConfig* altSyncConfig = enhPair.altSyncConfig.get();
- if (altSyncConfig)
- {
- TiXmlElement* xmlAltSyncCfg = new TiXmlElement("AlternateSyncConfig");
- newfolderPair->LinkEndChild(xmlAltSyncCfg);
+ in["SizeMax" ](filter.sizeMax);
+ in["UnitSizeMax"](filter.unitSizeMax);
+}
- //write sync configuration
- addXmlElement("Variant", altSyncConfig->syncConfiguration.var, xmlAltSyncCfg);
- TiXmlElement* syncDirections = new TiXmlElement("CustomDirections");
- xmlAltSyncCfg->LinkEndChild(syncDirections);
+void readConfig(const XmlIn& in, FolderPairEnh& enhPair)
+{
+ //read folder pairs
+ in["Left" ](enhPair.leftDirectory);
+ in["Right"](enhPair.rightDirectory);
- addXmlElement("LeftOnly", altSyncConfig->syncConfiguration.custom.exLeftSideOnly, syncDirections);
- addXmlElement("RightOnly", altSyncConfig->syncConfiguration.custom.exRightSideOnly, syncDirections);
- addXmlElement("LeftNewer", altSyncConfig->syncConfiguration.custom.leftNewer, syncDirections);
- addXmlElement("RightNewer", altSyncConfig->syncConfiguration.custom.rightNewer, syncDirections);
- addXmlElement("Different", altSyncConfig->syncConfiguration.custom.different, syncDirections);
- addXmlElement("Conflict", altSyncConfig->syncConfiguration.custom.conflict, syncDirections);
+ //###########################################################
+ //alternate sync configuration (optional)
+ XmlIn inAlt = in["AlternateSyncConfig"];
+ if (inAlt)
+ {
+ std::shared_ptr<AlternateSyncConfig> altSyncCfg = std::make_shared<AlternateSyncConfig>();
+ enhPair.altSyncConfig = altSyncCfg;
+
+ //read sync configuration
+ readConfig(inAlt, altSyncCfg->syncConfiguration);
- //misc
- addXmlElement("DeletionPolicy", altSyncConfig->handleDeletion, xmlAltSyncCfg);
- addXmlElement("CustomDeletionFolder", altSyncConfig->customDeletionDirectory, xmlAltSyncCfg);
+ inAlt["DeletionPolicy" ](altSyncCfg->handleDeletion);
+ inAlt["CustomDeletionFolder"](altSyncCfg->customDeletionDirectory);
}
//###########################################################
//alternate filter configuration
- TiXmlElement* filterCfg = new TiXmlElement("LocalFilter");
- newfolderPair->LinkEndChild(filterCfg);
-
- //write filter settings
- writeFilter(enhPair.localFilter, *filterCfg);
+ readConfig(in["LocalFilter"], enhPair.localFilter);
}
-void writeConfig(const MainConfiguration& mainCfg, TiXmlElement& root)
+void readConfig(const XmlIn& in, MainConfiguration& mainCfg)
{
- TiXmlElement* xmlMainCfg = new TiXmlElement("MainConfig");
- root.LinkEndChild(xmlMainCfg);
-
- //###########################################################
- TiXmlElement* cmpSettings = new TiXmlElement("Comparison");
- xmlMainCfg->LinkEndChild(cmpSettings);
+ XmlIn inCmp = in["MainConfig"]["Comparison"];
- //write compare algorithm
- addXmlElement("Variant", mainCfg.compareVar, cmpSettings);
+ //read compare variant
+ inCmp["Variant"](mainCfg.compareVar);
//include symbolic links at all?
- addXmlElement("HandleSymlinks", mainCfg.handleSymlinks, cmpSettings);
+ inCmp["HandleSymlinks"](mainCfg.handleSymlinks);
//###########################################################
- TiXmlElement* xmlSyncCfg = new TiXmlElement("SyncConfig");
- xmlMainCfg->LinkEndChild(xmlSyncCfg);
-
- //write sync configuration
- addXmlElement("Variant", mainCfg.syncConfiguration.var, xmlSyncCfg);
-
- TiXmlElement* syncDirections = new TiXmlElement("CustomDirections");
- xmlSyncCfg->LinkEndChild(syncDirections);
-
- addXmlElement("LeftOnly", mainCfg.syncConfiguration.custom.exLeftSideOnly, syncDirections);
- addXmlElement("RightOnly", mainCfg.syncConfiguration.custom.exRightSideOnly, syncDirections);
- addXmlElement("LeftNewer", mainCfg.syncConfiguration.custom.leftNewer, syncDirections);
- addXmlElement("RightNewer", mainCfg.syncConfiguration.custom.rightNewer, syncDirections);
- addXmlElement("Different", mainCfg.syncConfiguration.custom.different, syncDirections);
- addXmlElement("Conflict", mainCfg.syncConfiguration.custom.conflict, syncDirections);
+ XmlIn inSync = in["MainConfig"]["SyncConfig"];
+ //read sync configuration
+ readConfig(inSync, mainCfg.syncConfiguration);
//###########################################################
- //write filter settings
- TiXmlElement* filter = new TiXmlElement("GlobalFilter");
- xmlMainCfg->LinkEndChild(filter);
- writeFilter(mainCfg.globalFilter, *filter);
+ //misc
+ inSync["DeletionPolicy" ](mainCfg.handleDeletion);
+ inSync["CustomDeletionFolder"](mainCfg.customDeletionDirectory);
+ //###########################################################
- //other
- addXmlElement("DeletionPolicy", mainCfg.handleDeletion, xmlSyncCfg);
- addXmlElement("CustomDeletionFolder", mainCfg.customDeletionDirectory, xmlSyncCfg);
+ XmlIn inFilter = in["MainConfig"]["GlobalFilter"];
+ //read filter settings
+ readConfig(inFilter, mainCfg.globalFilter);
//###########################################################
- TiXmlElement* pairs = new TiXmlElement("FolderPairs");
- xmlMainCfg->LinkEndChild(pairs);
+ //read all folder pairs
+ mainCfg.additionalPairs.clear();
- //write first folder pair
- writeXmlLocalConfig(mainCfg.firstPair, *pairs);
+ bool firstIter = true;
+ for (XmlIn inPair = in["MainConfig"]["FolderPairs"]["Pair"]; inPair; inPair.next())
+ {
+ FolderPairEnh newPair;
+ readConfig(inPair, newPair);
- //write additional folder pairs
- for (std::vector<FolderPairEnh>::const_iterator i = mainCfg.additionalPairs.begin(); i != mainCfg.additionalPairs.end(); ++i)
- writeXmlLocalConfig(*i, *pairs);
+ if (firstIter)
+ {
+ firstIter = false;
+ mainCfg.firstPair = newPair; //set first folder pair
+ }
+ else
+ mainCfg.additionalPairs.push_back(newPair); //set additional folder pairs
+ }
}
-void writeConfig(const xmlAccess::XmlGuiConfig& inputCfg, TiXmlElement& root)
+void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
{
- //write main config
- writeConfig(inputCfg.mainCfg, root);
+ ::readConfig(in, config.mainCfg); //read main config
- //write GUI specific config
- TiXmlElement* guiConfig = new TiXmlElement("GuiConfig");
- root.LinkEndChild(guiConfig);
+ //read GUI specific config data
+ XmlIn inGuiCfg = in["GuiConfig"];
- addXmlElement("HideFiltered", inputCfg.hideFilteredElements, guiConfig);
- addXmlElement("HandleError", inputCfg.handleError, guiConfig);
- addXmlElement("SyncPreviewActive", inputCfg.syncPreviewEnabled, guiConfig);
+ inGuiCfg["HideFiltered" ](config.hideFilteredElements);
+ inGuiCfg["HandleError" ](config.handleError);
+ inGuiCfg["SyncPreviewActive"](config.syncPreviewEnabled);
}
-void writeConfig(const xmlAccess::XmlBatchConfig& inputCfg, TiXmlElement& root)
+void readConfig(const XmlIn& in, xmlAccess::XmlBatchConfig& config)
{
- //write main config
- writeConfig(inputCfg.mainCfg, root);
+ ::readConfig(in, config.mainCfg); //read main config
- //write GUI specific config
- TiXmlElement* batchConfig = new TiXmlElement("BatchConfig");
- root.LinkEndChild(batchConfig);
+ //read GUI specific config data
+ XmlIn inBatchCfg = in["BatchConfig"];
- addXmlElement("Silent", inputCfg.silent, batchConfig);
- addXmlElement("LogfileDirectory", inputCfg.logFileDirectory, batchConfig);
- addXmlElement("LogfileCountMax", inputCfg.logFileCountMax, batchConfig);
- addXmlElement("HandleError", inputCfg.handleError, batchConfig);
+ inBatchCfg["Silent" ](config.silent);
+ inBatchCfg["LogfileDirectory"](config.logFileDirectory);
+ inBatchCfg["LogfileCountMax" ](config.logFileCountMax);
+ inBatchCfg["HandleError" ](config.handleError);
}
-void writeConfig(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlElement& root)
+void readConfig(const XmlIn& in, XmlGlobalSettings& config)
{
- //write global settings
- TiXmlElement* global = new TiXmlElement("Shared");
- root.LinkEndChild(global);
+ XmlIn inShared = in["Shared"];
- //program language
- addXmlElement("Language", inputCfg.programLanguage, global);
+ //try to read program language setting
+ inShared["Language"](config.programLanguage);
//copy locked files using VSS
- addXmlElement("CopyLockedFiles", inputCfg.copyLockedFiles, global);
+ inShared["CopyLockedFiles"](config.copyLockedFiles);
//file permissions
- addXmlElement("CopyFilePermissions", inputCfg.copyFilePermissions, global);
+ inShared["CopyFilePermissions"](config.copyFilePermissions);
//verify file copying
- addXmlElement("VerifyCopiedFiles", inputCfg.verifyFileCopy, global);
+ inShared["VerifyCopiedFiles"](config.verifyFileCopy);
//max. allowed file time deviation
- addXmlElement("FileTimeTolerance", inputCfg.fileTimeTolerance, global);
-
-
- //optional dialogs
- TiXmlElement* optionalDialogs = new TiXmlElement("ShowOptionalDialogs");
- global->LinkEndChild(optionalDialogs);
-
- //warning: dependent folders
- addXmlElement("CheckForDependentFolders", inputCfg.optDialogs.warningDependentFolders, optionalDialogs);
-
- //check for multi write access for directory as part of multiple pairs
- addXmlElement("CheckForMultipleWriteAccess", inputCfg.optDialogs.warningMultiFolderWriteAccess, optionalDialogs);
-
- //significant difference check
- addXmlElement("CheckForSignificantDifference", inputCfg.optDialogs.warningSignificantDifference, optionalDialogs);
-
- //check free disk space
- addXmlElement("CheckForFreeDiskSpace", inputCfg.optDialogs.warningNotEnoughDiskSpace, optionalDialogs);
-
- //check for unresolved conflicts
- addXmlElement("CheckForUnresolvedConflicts", inputCfg.optDialogs.warningUnresolvedConflicts, optionalDialogs);
-
- addXmlElement("NotifyDatabaseError", inputCfg.optDialogs.warningSyncDatabase, optionalDialogs);
-
- addXmlElement("PopupOnConfigChange", inputCfg.optDialogs.popupOnConfigChange, optionalDialogs);
-
- addXmlElement("SummaryBeforeSync", inputCfg.optDialogs.showSummaryBeforeSync, optionalDialogs);
-
-
- //###################################################################
- //write global gui settings
- TiXmlElement* gui = new TiXmlElement("Gui");
- root.LinkEndChild(gui);
-
- TiXmlElement* windows = new TiXmlElement("Windows");
- gui->LinkEndChild(windows);
+ inShared["FileTimeTolerance"](config.fileTimeTolerance);
+
+ XmlIn inOpt = inShared["ShowOptionalDialogs"];
+ inOpt["CheckForDependentFolders" ](config.optDialogs.warningDependentFolders);
+ inOpt["CheckForMultipleWriteAccess" ](config.optDialogs.warningMultiFolderWriteAccess);
+ inOpt["CheckForSignificantDifference"](config.optDialogs.warningSignificantDifference);
+ inOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
+ inOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
+ inOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
+ inOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
+ inOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
- TiXmlElement* mainWindow = new TiXmlElement("Main");
- windows->LinkEndChild(mainWindow);
+ //gui specific global settings (optional)
+ XmlIn inGui = in["Gui"];
+ XmlIn inWnd = inGui["Windows"]["Main"];
- //window size
- addXmlElement("Width", inputCfg.gui.widthNotMaximized, mainWindow);
- addXmlElement("Height", inputCfg.gui.heightNotMaximized, mainWindow);
+ //read application window size and position
+ inWnd["Width" ](config.gui.dlgSize.x);
+ inWnd["Height" ](config.gui.dlgSize.y);
+ inWnd["PosX" ](config.gui.dlgPos.x);
+ inWnd["PosY" ](config.gui.dlgPos.y);
+ inWnd["Maximized"](config.gui.isMaximized);
- //window position
- addXmlElement("PosX", inputCfg.gui.posXNotMaximized, mainWindow);
- addXmlElement("PosY", inputCfg.gui.posYNotMaximized, mainWindow);
- addXmlElement("Maximized", inputCfg.gui.isMaximized, mainWindow);
+ inWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
+ inWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
+ inWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
- addXmlElement("ManualDeletionOnBothSides", inputCfg.gui.deleteOnBothSides, mainWindow);
- addXmlElement("ManualDeletionUseRecycler", inputCfg.gui.useRecyclerForManualDeletion, mainWindow);
+ //###########################################################
- addXmlElement("RespectCaseOnSearch", inputCfg.gui.textSearchRespectCase, mainWindow);
+ //read column attributes
+ XmlIn inColLeft = inWnd["LeftColumns"];
- addXmlElement("FolderPairsMax", inputCfg.gui.addFolderPairCountMax + 1 /*add main pair*/, mainWindow);
+ inColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft);
+ inColLeft.attribute("ShowFileIcons", config.gui.showFileIconsLeft);
+ inColLeft(config.gui.columnAttribLeft);
+ for (size_t i = 0; i < config.gui.columnAttribLeft.size(); ++i)
+ config.gui.columnAttribLeft[i].position = i;
- //write column attributes
- TiXmlElement* leftColumn = new TiXmlElement("LeftColumns");
- mainWindow->LinkEndChild(leftColumn);
-
- addXmlAttribute("AutoAdjust", inputCfg.gui.autoAdjustColumnsLeft, leftColumn);
- addXmlAttribute("ShowFileIcons", inputCfg.gui.showFileIconsLeft, leftColumn);
+ //###########################################################
+ XmlIn inColRight = inWnd["RightColumns"];
- ColumnAttributes columnAtrribLeftCopy = inputCfg.gui.columnAttribLeft; //can't change const vector
- sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByPositionOnly);
- for (size_t i = 0; i < columnAtrribLeftCopy.size(); ++i)
- {
- TiXmlElement* subElement = new TiXmlElement("Column");
- leftColumn->LinkEndChild(subElement);
+ inColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight);
+ inColRight.attribute("ShowFileIcons", config.gui.showFileIconsRight);
- const ColumnAttrib& colAttrib = columnAtrribLeftCopy[i];
- addXmlAttribute("Type", colAttrib.type, subElement);
- addXmlAttribute("Visible", colAttrib.visible, subElement);
- addXmlAttribute("Width", colAttrib.width, subElement);
- }
+ inColRight(config.gui.columnAttribRight);
+ for (size_t i = 0; i < config.gui.columnAttribRight.size(); ++i)
+ config.gui.columnAttribRight[i].position = i;
- TiXmlElement* rightColumn = new TiXmlElement("RightColumns");
- mainWindow->LinkEndChild(rightColumn);
+ inWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft);
+ inWnd["FolderHistoryRight"](config.gui.folderHistoryRight);
+ inWnd["MaximumHistorySize"](config.gui.folderHistMax);
+ inWnd["Perspective" ](config.gui.guiPerspectiveLast);
- addXmlAttribute("AutoAdjust", inputCfg.gui.autoAdjustColumnsRight, rightColumn);
- addXmlAttribute("ShowFileIcons", inputCfg.gui.showFileIconsRight, rightColumn);
+ //external applications
+ inGui["ExternalApplications"](config.gui.externelApplications);
- ColumnAttributes columnAtrribRightCopy = inputCfg.gui.columnAttribRight;
- sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByPositionOnly);
- for (size_t i = 0; i < columnAtrribRightCopy.size(); ++i)
- {
- TiXmlElement* subElement = new TiXmlElement("Column");
- rightColumn->LinkEndChild(subElement);
+ //load config file history
+ XmlIn inHist = inGui["ConfigHistory"];
- const ColumnAttrib& colAttrib = columnAtrribRightCopy[i];
- addXmlAttribute("Type", colAttrib.type, subElement);
- addXmlAttribute("Visible", colAttrib.visible, subElement);
- addXmlAttribute("Width", colAttrib.width, subElement);
- }
+ inHist.attribute("LastUsed", config.gui.lastUsedConfigFile);
+ inHist(config.gui.cfgFileHistory);
- addXmlElement("FolderHistoryLeft", inputCfg.gui.folderHistoryLeft , mainWindow);
- addXmlElement("FolderHistoryRight", inputCfg.gui.folderHistoryRight, mainWindow);
- addXmlElement("MaximumHistorySize", inputCfg.gui.folderHistMax , mainWindow);
+ //last update check
+ inGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
- addXmlElement("Perspective", inputCfg.gui.guiPerspectiveLast, mainWindow);
+ //batch specific global settings
+ //XmlIn inBatch = in["Batch"];
+}
- //external applications
- TiXmlElement* extApp = new TiXmlElement("ExternalApplications");
- gui->LinkEndChild(extApp);
- for (ExternalApps::const_iterator i = inputCfg.gui.externelApplications.begin(); i != inputCfg.gui.externelApplications.end(); ++i)
- {
- TiXmlElement* newEntry = new TiXmlElement("Commandline");
- extApp->LinkEndChild(newEntry);
+template <class ConfigType>
+void readConfig(const wxString& filename, XmlType type, ConfigType& config)
+{
+ if (!fileExists(wxToZ(filename)))
+ throw FfsXmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
- addXmlAttribute("Description", i->first, newEntry);
- newEntry->LinkEndChild(new TiXmlText(i->second.ToUTF8())); //commandline
- }
+ XmlDoc doc;
+ loadXmlDocument(filename, doc); //throw (FfsXmlError)
- //write config file history
- TiXmlElement* cfgHistory = new TiXmlElement("ConfigHistory");
- gui->LinkEndChild(cfgHistory);
+ if (getXmlType(doc) != type) //throw()
+ throw FfsXmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
- addXmlAttribute("LastUsed", inputCfg.gui.lastUsedConfigFile, cfgHistory);
- addXmlElement("File", inputCfg.gui.cfgFileHistory, cfgHistory);
+ XmlIn in(doc);
+ ::readConfig(in, config);
- //last update check
- addXmlElement("LastUpdateCheck", inputCfg.gui.lastUpdateCheck, gui);
+ if (in.errorsOccured())
+ throw FfsXmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
+ getErrorMessageFormatted(in), FfsXmlError::WARNING);
+}
+}
- //###################################################################
- //write global batch settings
- TiXmlElement* batch = new TiXmlElement("Batch");
- root.LinkEndChild(batch);
+void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
+{
+ ::readConfig(filename, XML_TYPE_GUI, config);
}
-wxString xmlAccess::getGlobalConfigFile()
+void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlBatchConfig& config)
{
- return zen::getConfigDir() + wxT("GlobalSettings.xml");
+ ::readConfig(filename, XML_TYPE_BATCH, config);
}
-void xmlAccess::OptionalDialogs::resetDialogs()
+void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
{
- warningDependentFolders = true;
- warningMultiFolderWriteAccess = true;
- warningSignificantDifference = true;
- warningNotEnoughDiskSpace = true;
- warningUnresolvedConflicts = true;
- warningSyncDatabase = true;
- popupOnConfigChange = true;
- showSummaryBeforeSync = true;
+ ::readConfig(getGlobalConfigFile(), XML_TYPE_GLOBAL, config);
}
-xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchConfig& batchCfg)
+//################################################################################################
+namespace
{
- XmlGuiConfig output;
- output.mainCfg = batchCfg.mainCfg;
- return output;
+void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
+{
+ out["Variant"](syncCfg.var);
+
+ XmlOut outCustDir = out["CustomDirections"];
+ outCustDir["LeftOnly" ](syncCfg.custom.exLeftSideOnly);
+ outCustDir["RightOnly" ](syncCfg.custom.exRightSideOnly);
+ outCustDir["LeftNewer" ](syncCfg.custom.leftNewer);
+ outCustDir["RightNewer"](syncCfg.custom.rightNewer);
+ outCustDir["Different" ](syncCfg.custom.different);
+ outCustDir["Conflict" ](syncCfg.custom.conflict);
}
-xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg)
+void writeConfig(const FilterConfig& filter, XmlOut& out)
{
- XmlBatchConfig output;
- output.mainCfg = guiCfg.mainCfg;
+ out["Include"](filter.includeFilter);
+ out["Exclude"](filter.excludeFilter);
- switch (guiCfg.handleError)
- {
- case ON_GUIERROR_POPUP:
- output.handleError = xmlAccess::ON_ERROR_POPUP;
- break;
- case ON_GUIERROR_IGNORE:
- output.handleError = xmlAccess::ON_ERROR_IGNORE;
- break;
- }
+ out["TimeSpan" ](filter.timeSpan);
+ out["UnitTimeSpan"](filter.unitTimeSpan);
- return output;
+ out["SizeMin" ](filter.sizeMin);
+ out["UnitSizeMin"](filter.unitSizeMin);
+
+ out["SizeMax" ](filter.sizeMax);
+ out["UnitSizeMax"](filter.unitSizeMax);
}
-xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filenames) //throw ()
+void writeConfigFolderPair(const FolderPairEnh& enhPair, XmlOut& out)
{
- bool guiCfgExists = false;
- bool batchCfgExists = false;
+ XmlOut outPair = out.ref().addChild("Pair");
- for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
+ //read folder pairs
+ outPair["Left" ](enhPair.leftDirectory);
+ outPair["Right"](enhPair.rightDirectory);
+
+ //###########################################################
+ //alternate sync configuration (optional)
+ if (enhPair.altSyncConfig.get())
{
- switch (xmlAccess::getXmlType(*i)) //throw()
- {
- case XML_TYPE_GUI:
- guiCfgExists = true;
- break;
+ XmlOut outAlt = outPair["AlternateSyncConfig"];
- case XML_TYPE_BATCH:
- batchCfgExists = true;
- break;
+ //read sync configuration
+ writeConfig(enhPair.altSyncConfig->syncConfiguration, outAlt);
- case XML_TYPE_GLOBAL:
- case XML_TYPE_OTHER:
- return MERGE_OTHER;
- }
+ outAlt["DeletionPolicy" ](enhPair.altSyncConfig->handleDeletion);
+ outAlt["CustomDeletionFolder"](enhPair.altSyncConfig->customDeletionDirectory);
}
- if (guiCfgExists && batchCfgExists)
- return MERGE_GUI_BATCH;
- else if (guiCfgExists && !batchCfgExists)
- return MERGE_GUI;
- else if (!guiCfgExists && batchCfgExists)
- return MERGE_BATCH;
- else
- return MERGE_OTHER;
+ //###########################################################
+ //alternate filter configuration
+ XmlOut outFilter = outPair["LocalFilter"];
+ writeConfig(enhPair.localFilter, outFilter);
}
-namespace
-{
-template <class XmlCfg>
-XmlCfg loadCfgImpl(const wxString& filename, std::auto_ptr<xmlAccess::XmlError>& exeption) //throw (xmlAccess::XmlError)
+void writeConfig(const MainConfiguration& mainCfg, XmlOut& out)
{
- XmlCfg cfg;
- try
- {
- xmlAccess::readConfig(filename, cfg); //throw (xmlAccess::XmlError);
- }
- catch (const xmlAccess::XmlError& e)
- {
- if (e.getSeverity() == xmlAccess::XmlError::FATAL)
- throw;
- else
- exeption.reset(new xmlAccess::XmlError(e));
- }
- return cfg;
-}
+ XmlOut outCmp = out["MainConfig"]["Comparison"];
+ //write compare variant
+ outCmp["Variant"](mainCfg.compareVar);
-template <class XmlCfg>
-void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config) //throw (xmlAccess::XmlError)
-{
- using namespace xmlAccess;
-
- assert(!filenames.empty());
- if (filenames.empty())
- return;
+ //include symbolic links at all?
+ outCmp["HandleSymlinks"](mainCfg.handleSymlinks);
- std::vector<zen::MainConfiguration> mainCfgs;
- std::auto_ptr<XmlError> savedException;
+ //###########################################################
+ XmlOut outSync = out["MainConfig"]["SyncConfig"];
- for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
- {
- switch (getXmlType(*i))
- {
- case XML_TYPE_GUI:
- mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(*i, savedException).mainCfg); //throw (xmlAccess::XmlError)
- break;
+ //write sync configuration
+ writeConfig(mainCfg.syncConfiguration, outSync);
+ //###########################################################
- case XML_TYPE_BATCH:
- mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(*i, savedException).mainCfg); //throw (xmlAccess::XmlError)
- break;
+ //misc
+ outSync["DeletionPolicy" ](mainCfg.handleDeletion);
+ outSync["CustomDeletionFolder"](mainCfg.customDeletionDirectory);
+ //###########################################################
- case XML_TYPE_GLOBAL:
- case XML_TYPE_OTHER:
- break;
- }
- }
+ XmlOut outFilter = out["MainConfig"]["GlobalFilter"];
+ //write filter settings
+ writeConfig(mainCfg.globalFilter, outFilter);
- if (mainCfgs.empty())
- throw XmlError(_("Invalid FreeFileSync config file!"));
+ //###########################################################
+ //write all folder pairs
- try //...to init all non-"mainCfg" settings with first config file
- {
- xmlAccess::readConfig(filenames[0], config); //throw (xmlAccess::XmlError);
- }
- catch (...) {}
+ XmlOut outFp = out["MainConfig"]["FolderPairs"];
- config.mainCfg = merge(mainCfgs);
+ //write first folder pair
+ writeConfigFolderPair(mainCfg.firstPair, outFp);
- if (savedException.get()) //"re-throw" exception
- throw* savedException;
-}
+ //write additional folder pairs
+ std::for_each(mainCfg.additionalPairs.begin(), mainCfg.additionalPairs.end(),
+ [&](const FolderPairEnh& fp) { writeConfigFolderPair(fp, outFp); });
}
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config) //throw (xmlAccess::XmlError)
+void writeConfig(const XmlGuiConfig& config, XmlOut& out)
{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::XmlError)
-}
+ writeConfig(config.mainCfg, out); //write main config
+ //write GUI specific config data
+ XmlOut outGuiCfg = out["GuiConfig"];
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config) //throw (xmlAccess::XmlError);
-{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::XmlError)
+ outGuiCfg["HideFiltered" ](config.hideFilteredElements);
+ outGuiCfg["HandleError" ](config.handleError);
+ outGuiCfg["SyncPreviewActive"](config.syncPreviewEnabled);
}
+void writeConfig(const XmlBatchConfig& config, XmlOut& out)
+{
+ writeConfig(config.mainCfg, out); //write main config
+ //write GUI specific config data
+ XmlOut outBatchCfg = out["BatchConfig"];
+ outBatchCfg["Silent" ](config.silent);
+ outBatchCfg["LogfileDirectory"](config.logFileDirectory);
+ outBatchCfg["LogfileCountMax" ](config.logFileCountMax);
+ outBatchCfg["HandleError" ](config.handleError);
+}
-
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
+void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
{
- //load XML
- if (!fileExists(wxToZ(filename)))
- throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
+ XmlOut outShared = out["Shared"];
- TiXmlDocument doc;
- loadXmlDocument(filename, doc); //throw (XmlError)
+ //write program language setting
+ outShared["Language"](config.programLanguage);
- if (getXmlType(doc) != XML_TYPE_GUI) //throw()
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
+ //copy locked files using VSS
+ outShared["CopyLockedFiles"](config.copyLockedFiles);
- FfsXmlErrorLogger logger;
- logger.readConfig(doc.RootElement(), config); //read GUI layout configuration
+ //file permissions
+ outShared["CopyFilePermissions"](config.copyFilePermissions);
- if (logger.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
- logger.getErrorMessageFormatted(), XmlError::WARNING);
-}
+ //verify file copying
+ outShared["VerifyCopiedFiles"](config.verifyFileCopy);
+ //max. allowed file time deviation
+ outShared["FileTimeTolerance"](config.fileTimeTolerance);
+
+ XmlOut outOpt = outShared["ShowOptionalDialogs"];
+ outOpt["CheckForDependentFolders" ](config.optDialogs.warningDependentFolders);
+ outOpt["CheckForMultipleWriteAccess" ](config.optDialogs.warningMultiFolderWriteAccess);
+ outOpt["CheckForSignificantDifference"](config.optDialogs.warningSignificantDifference);
+ outOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
+ outOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
+ outOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
+ outOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
+ outOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlBatchConfig& config)
-{
- //load XML
- if (!fileExists(wxToZ(filename)))
- throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
+ //gui specific global settings (optional)
+ XmlOut outGui = out["Gui"];
+ XmlOut outWnd = outGui["Windows"]["Main"];
- TiXmlDocument doc;
- loadXmlDocument(filename, doc); //throw (XmlError)
+ //write application window size and position
+ outWnd["Width" ](config.gui.dlgSize.x);
+ outWnd["Height" ](config.gui.dlgSize.y);
+ outWnd["PosX" ](config.gui.dlgPos.x);
+ outWnd["PosY" ](config.gui.dlgPos.y);
+ outWnd["Maximized"](config.gui.isMaximized);
- if (getXmlType(doc) != XML_TYPE_BATCH) //throw()
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
+ outWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
+ outWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
+ outWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
- FfsXmlErrorLogger logger;
- logger.readConfig(doc.RootElement(), config); //read GUI layout configuration
+ //###########################################################
- if (logger.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
- logger.getErrorMessageFormatted(), XmlError::WARNING);
-}
+ //write column attributes
+ XmlOut outColLeft = outWnd["LeftColumns"];
+ outColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft);
+ outColLeft.attribute("ShowFileIcons", config.gui.showFileIconsLeft);
-void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
-{
- //load XML
- if (!fileExists(wxToZ(getGlobalConfigFile())))
- throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+ outColLeft(config.gui.columnAttribLeft);
- TiXmlDocument doc;
- loadXmlDocument(getGlobalConfigFile(), doc); //throw (XmlError)
+ //###########################################################
+ XmlOut outColRight = outWnd["RightColumns"];
- if (getXmlType(doc) != XML_TYPE_GLOBAL) //throw()
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+ outColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight);
+ outColRight.attribute("ShowFileIcons", config.gui.showFileIconsRight);
- FfsXmlErrorLogger logger;
- logger.readConfig(doc.RootElement(), config); //read GUI layout configuration
+ outColRight(config.gui.columnAttribRight);
- if (logger.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\"\n\n") +
- logger.getErrorMessageFormatted(), XmlError::WARNING);
-}
+ outWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft);
+ outWnd["FolderHistoryRight"](config.gui.folderHistoryRight);
+ outWnd["MaximumHistorySize"](config.gui.folderHistMax);
+ outWnd["Perspective" ](config.gui.guiPerspectiveLast);
+ //external applications
+ outGui["ExternalApplications"](config.gui.externelApplications);
-void xmlAccess::writeConfig(const XmlGuiConfig& outputCfg, const wxString& filename)
-{
- TiXmlDocument doc;
- initXmlDocument(doc, XML_TYPE_GUI); //throw()
+ //load config file history
+ XmlOut outHist = outGui["ConfigHistory"];
- if (!doc.RootElement())
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
+ outHist.attribute("LastUsed", config.gui.lastUsedConfigFile);
+ outHist(config.gui.cfgFileHistory);
- writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
+ //last update check
+ outGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
- saveXmlDocument(filename, doc); //throw (XmlError)
+ //batch specific global settings
+ //XmlOut outBatch = out["Batch"];
}
-void xmlAccess::writeConfig(const XmlBatchConfig& outputCfg, const wxString& filename)
+template <class ConfigType>
+void writeConfig(const ConfigType& config, XmlType type, const wxString& filename)
{
- TiXmlDocument doc;
- initXmlDocument(doc, XML_TYPE_BATCH); //throw()
+ XmlDoc doc("FreeFileSync");
+ setXmlType(doc, type); //throw()
- if (!doc.RootElement())
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
+ XmlOut out(doc);
+ writeConfig(config, out);
- writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
+ saveXmlDocument(doc, filename); //throw (FfsXmlError)
+}
+}
- saveXmlDocument(filename, doc); //throw (XmlError)
+void xmlAccess::writeConfig(const XmlGuiConfig& config, const wxString& filename)
+{
+ ::writeConfig(config, XML_TYPE_GUI, filename); //throw (FfsXmlError)
}
-void xmlAccess::writeConfig(const XmlGlobalSettings& outputCfg)
+void xmlAccess::writeConfig(const XmlBatchConfig& config, const wxString& filename)
{
- TiXmlDocument doc;
- initXmlDocument(doc, XML_TYPE_GLOBAL); //throw()
-
- if (!doc.RootElement())
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+ ::writeConfig(config, XML_TYPE_BATCH, filename); //throw (FfsXmlError)
+}
- writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
- saveXmlDocument(getGlobalConfigFile(), doc); //throw (XmlError)
+void xmlAccess::writeConfig(const XmlGlobalSettings& config)
+{
+ ::writeConfig(config, XML_TYPE_GLOBAL, getGlobalConfigFile()); //throw (FfsXmlError)
}
bgstack15