summaryrefslogtreecommitdiff
path: root/lib/process_xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/process_xml.cpp')
-rw-r--r--lib/process_xml.cpp400
1 files changed, 251 insertions, 149 deletions
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index d41afc74..4974dcbc 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -1,4 +1,4 @@
-// **************************************************************************
+// **************************************************************************
// * 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) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
@@ -17,6 +17,14 @@ using namespace xmlAccess; //functionally needed for correct overload resolution
using namespace std::rel_ops;
+namespace
+{
+//-------------------------------------------------------------------------------------------------------------------------------
+const int XML_FORMAT_VER_GLOBAL = 1;
+const int XML_FORMAT_VER_FFS_GUI = 1;
+const int XML_FORMAT_VER_FFS_BATCH = 1;
+//-------------------------------------------------------------------------------------------------------------------------------
+}
XmlType getXmlType(const zen::XmlDoc& doc) //throw()
{
@@ -73,9 +81,9 @@ void setXmlType(XmlDoc& doc, XmlType type) //throw()
}
//################################################################################################################
-wxString xmlAccess::getGlobalConfigFile()
+Zstring xmlAccess::getGlobalConfigFile()
{
- return utfCvrtTo<wxString>(zen::getConfigDir()) + L"GlobalSettings.xml";
+ return zen::getConfigDir() + Zstr("GlobalSettings.xml");
}
@@ -88,6 +96,8 @@ void xmlAccess::OptionalDialogs::resetDialogs()
warningUnresolvedConflicts = true;
warningDatabaseError = true;
warningRecyclerMissing = true;
+ warningInputFieldEmpty = true;
+ warningDirectoryLockFailed = true;
popupOnConfigChange = true;
confirmSyncStart = true;
}
@@ -180,67 +190,21 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<Zstring>& filenam
namespace
{
-template <class XmlCfg>
-XmlCfg readConfigNoWarnings(const Zstring& filename, std::unique_ptr<FfsXmlError>& warning) //throw FfsXmlError, but only if "FATAL"
+std::vector<Zstring> splitFilterByLines(const Zstring& filterPhrase)
{
- XmlCfg cfg;
- try
- {
- readConfig(filename, cfg); //throw xmlAccess::FfsXmlError
- }
- catch (const FfsXmlError& e)
- {
- if (e.getSeverity() == FfsXmlError::FATAL)
- throw;
- else if (!warning.get()) warning = make_unique<FfsXmlError>(e);
- }
- return cfg;
+ if (filterPhrase.empty())
+ return std::vector<Zstring>();
+ return split(filterPhrase, Zstr('\n'));
}
-}
-
-void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config) //throw FfsXmlError
+Zstring mergeFilterLines(const std::vector<Zstring>& filterLines)
{
- assert(!filenames.empty());
-
- std::vector<zen::MainConfiguration> mainCfgs;
- std::unique_ptr<FfsXmlError> savedWarning;
-
- for (auto it = filenames.begin(); it != filenames.end(); ++it)
- {
- const Zstring& filename = *it;
- const bool firstLine = it == filenames.begin(); //init all non-"mainCfg" settings with first config file
-
- switch (getXmlType(filename))
- {
- case XML_TYPE_GUI:
- if (firstLine)
- config = readConfigNoWarnings<XmlGuiConfig>(filename, savedWarning);
- else
- mainCfgs.push_back(readConfigNoWarnings<XmlGuiConfig>(filename, savedWarning).mainCfg); //throw FfsXmlError
- break;
-
- case XML_TYPE_BATCH:
- if (firstLine)
- config = convertBatchToGui(readConfigNoWarnings<XmlBatchConfig>(filename, savedWarning));
- else
- mainCfgs.push_back(readConfigNoWarnings<XmlBatchConfig>(filename, savedWarning).mainCfg); //throw FfsXmlError
- break;
-
- case XML_TYPE_GLOBAL:
- case XML_TYPE_OTHER:
- if (!fileExists(filename))
- throw FfsXmlError(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)));
- else
- throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
- }
- }
- mainCfgs.push_back(config.mainCfg); //save cfg from first line
-
- config.mainCfg = merge(mainCfgs);
-
- if (savedWarning.get()) //"re-throw" exception
- throw* savedWarning;
+ if (filterLines.empty())
+ return Zstring();
+ Zstring out = filterLines[0];
+ std::for_each(filterLines.begin() + 1, filterLines.end(), [&](const Zstring& line) { out += Zstr('\n'); out += line; });
+ return out;
+}
}
@@ -594,6 +558,9 @@ void writeText(const ColumnTypeNavi& value, std::string& output)
case COL_TYPE_NAVI_DIRECTORY:
output = "Tree";
break;
+ case COL_TYPE_NAVI_ITEM_COUNT:
+ output = "Count";
+ break;
}
}
@@ -606,6 +573,8 @@ bool readText(const std::string& input, ColumnTypeNavi& value)
value = COL_TYPE_NAVI_BYTES;
else if (tmp == "Tree")
value = COL_TYPE_NAVI_DIRECTORY;
+ else if (tmp == "Count")
+ value = COL_TYPE_NAVI_ITEM_COUNT;
else
return false;
return true;
@@ -870,8 +839,33 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg)
void readConfig(const XmlIn& in, FilterConfig& filter)
{
- in["Include"](filter.includeFilter);
- in["Exclude"](filter.excludeFilter);
+ warn_static("remove after migration?")
+ auto haveFilterAsSingleString = [&]() -> bool
+ {
+ if (in["Include"])
+ if (auto elem = in["Include"].get())
+ {
+ std::string tmp;
+ if (elem->getValue(tmp))
+ return !tmp.empty();
+ }
+ return false;
+ };
+ if (haveFilterAsSingleString()) //obsolete style
+ {
+ in["Include"](filter.includeFilter);
+ in["Exclude"](filter.excludeFilter);
+ }
+ else
+ {
+ std::vector<Zstring> tmp = splitFilterByLines(filter.includeFilter); //default value
+ in["Include"](tmp);
+ filter.includeFilter = mergeFilterLines(tmp);
+
+ std::vector<Zstring> tmp2 = splitFilterByLines(filter.excludeFilter); //default value
+ in["Exclude"](tmp2);
+ filter.excludeFilter = mergeFilterLines(tmp2);
+ }
in["TimeSpan"](filter.timeSpan);
warn_static("remove after migration?")
@@ -942,15 +936,15 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg)
//read all folder pairs
mainCfg.additionalPairs.clear();
- bool firstIter = true;
+ bool firstItem = true;
for (XmlIn inPair = inMain["FolderPairs"]["Pair"]; inPair; inPair.next())
{
FolderPairEnh newPair;
readConfig(inPair, newPair);
- if (firstIter)
+ if (firstItem)
{
- firstIter = false;
+ firstItem = false;
mainCfg.firstPair = newPair; //set first folder pair
}
else
@@ -966,7 +960,7 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg)
void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
{
- ::readConfig(in, config.mainCfg); //read main config
+ readConfig(in, config.mainCfg); //read main config
//read GUI specific config data
XmlIn inGuiCfg = in["GuiConfig"];
@@ -998,7 +992,7 @@ void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
void readConfig(const XmlIn& in, xmlAccess::XmlBatchConfig& config)
{
- ::readConfig(in, config.mainCfg); //read main config
+ readConfig(in, config.mainCfg); //read main config
//read GUI specific config data
XmlIn inBatchCfg = in["BatchConfig"];
@@ -1021,31 +1015,29 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
{
XmlIn inShared = in["Shared"];
- //try to read program language setting
- inShared["Language"](config.programLanguage);
-
- inShared["CopyLockedFiles" ](config.copyLockedFiles);
- inShared["CopyFilePermissions" ](config.copyFilePermissions);
- inShared["TransactionalFileCopy"](config.transactionalFileCopy);
- inShared["LockDirectoriesDuringSync"](config.createLockFile);
- inShared["VerifyCopiedFiles" ](config.verifyFileCopy);
- inShared["RunWithBackgroundPriority"](config.runWithBackgroundPriority);
+ inShared["Language"].attribute("id", config.programLanguage);
- //max. allowed file time deviation
- inShared["FileTimeTolerance"](config.fileTimeTolerance);
-
- inShared["LastSyncsFileSizeMax"](config.lastSyncsLogFileSizeMax);
+ inShared["FailSafeFileCopy" ].attribute("Enabled", config.transactionalFileCopy);
+ inShared["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles);
+ inShared["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions);
+ inShared["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority);
+ inShared["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile);
+ inShared["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy);
+ inShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance);
+ inShared["LastSyncsLogSizeMax" ].attribute("Bytes" , config.lastSyncsLogFileSizeMax);
XmlIn inOpt = inShared["OptionalDialogs"];
- inOpt["WarnUnresolvedConflicts" ](config.optDialogs.warningUnresolvedConflicts);
- inOpt["WarnNotEnoughDiskSpace" ](config.optDialogs.warningNotEnoughDiskSpace);
- inOpt["WarnSignificantDifference" ](config.optDialogs.warningSignificantDifference);
- inOpt["WarnRecycleBinNotAvailable" ](config.optDialogs.warningRecyclerMissing);
- inOpt["WarnDatabaseError" ](config.optDialogs.warningDatabaseError);
- inOpt["WarnDependentFolders" ](config.optDialogs.warningDependentFolders);
- inOpt["WarnFolderPairRaceCondition"](config.optDialogs.warningFolderPairRaceCondition);
- inOpt["PromptSaveConfig" ](config.optDialogs.popupOnConfigChange);
- inOpt["ConfirmSyncStart" ](config.optDialogs.confirmSyncStart);
+ inOpt["WarnUnresolvedConflicts" ].attribute("Enabled", config.optDialogs.warningUnresolvedConflicts);
+ inOpt["WarnNotEnoughDiskSpace" ].attribute("Enabled", config.optDialogs.warningNotEnoughDiskSpace);
+ inOpt["WarnSignificantDifference" ].attribute("Enabled", config.optDialogs.warningSignificantDifference);
+ inOpt["WarnRecycleBinNotAvailable" ].attribute("Enabled", config.optDialogs.warningRecyclerMissing);
+ inOpt["WarnInputFieldEmpty" ].attribute("Enabled", config.optDialogs.warningInputFieldEmpty);
+ inOpt["WarnDatabaseError" ].attribute("Enabled", config.optDialogs.warningDatabaseError);
+ inOpt["WarnDependentFolders" ].attribute("Enabled", config.optDialogs.warningDependentFolders);
+ inOpt["WarnFolderPairRaceCondition"].attribute("Enabled", config.optDialogs.warningFolderPairRaceCondition);
+ inOpt["WarnDirectoryLockFailed" ].attribute("Enabled", config.optDialogs.warningDirectoryLockFailed);
+ inOpt["ConfirmSaveConfig" ].attribute("Enabled", config.optDialogs.popupOnConfigChange);
+ inOpt["ConfirmStartSync" ].attribute("Enabled", config.optDialogs.confirmSyncStart);
//gui specific global settings (optional)
XmlIn inGui = in["Gui"];
@@ -1062,24 +1054,25 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
//inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
inManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
- inWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
- inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
+ inWnd["CaseSensitiveSearch"].attribute("Enabled", config.gui.textSearchRespectCase);
+ inWnd["FolderPairsVisible" ].attribute("Max", config.gui.maxFolderPairsVisible);
//###########################################################
+
+ XmlIn inOverview = inWnd["OverviewPanel"];
+ inOverview.attribute("ShowPercentage", config.gui.showPercentBar);
+ inOverview.attribute("SortByColumn", config.gui.naviLastSortColumn);
+ inOverview.attribute("SortAscending", config.gui.naviLastSortAscending);
+
//read column attributes
- XmlIn inColNavi = inWnd["OverviewColumns"];
+ XmlIn inColNavi = inOverview["Columns"];
inColNavi(config.gui.columnAttribNavi);
- inColNavi.attribute("ShowPercentage", config.gui.showPercentBar);
- inColNavi.attribute("SortByColumn", config.gui.naviLastSortColumn);
- inColNavi.attribute("SortAscending", config.gui.naviLastSortAscending);
-
XmlIn inMainGrid = inWnd["MainGrid"];
inMainGrid.attribute("ShowIcons", config.gui.showIcons);
inMainGrid.attribute("IconSize", config.gui.iconSize);
inMainGrid.attribute("SashOffset", config.gui.sashOffset);
-
XmlIn inColLeft = inMainGrid["ColumnsLeft"];
inColLeft(config.gui.columnAttribLeft);
@@ -1088,11 +1081,14 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
//###########################################################
inWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
- inWnd["Layout" ](config.gui.guiPerspectiveLast);
+ inWnd["Perspective" ](config.gui.guiPerspectiveLast);
- //load config file history
- inGui["LastUsedConfig"](config.gui.lastUsedConfigFiles);
+ std::vector<Zstring> tmp = splitFilterByLines(config.gui.defaultExclusionFilter); //default value
+ inGui["DefaultExclusionFilter"](tmp);
+ config.gui.defaultExclusionFilter = mergeFilterLines(tmp);
+ //load config file history
+ inGui["LastUsedConfig"](config.gui.lastUsedConfigFiles);
inGui["ConfigHistory"](config.gui.cfgFileHistory);
inGui["ConfigHistory"].attribute("MaxSize", config.gui.cfgFileHistMax);
@@ -1114,44 +1110,146 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
}
+bool needsMigration(const XmlDoc& doc, int currentXmlFormatVer)
+{
+ //(try to) migrate old configuration if needed
+ int xmlFormatVer = 0;
+ /*bool success = */doc.root().getAttribute("XmlFormat", xmlFormatVer);
+ return xmlFormatVer < currentXmlFormatVer;
+}
+
+
template <class ConfigType>
-void readConfig(const Zstring& filename, XmlType type, ConfigType& config)
+void readConfig(const Zstring& filename, XmlType type, ConfigType& cfg, int currentXmlFormatVer, bool& needMigration) //throw FfsXmlError
{
XmlDoc doc;
loadXmlDocument(filename, doc); //throw FfsXmlError
-
+
if (getXmlType(doc) != type) //throw()
throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
XmlIn in(doc);
- ::readConfig(in, config);
+ ::readConfig(in, cfg);
if (in.errorsOccured())
throw FfsXmlError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" +
- getErrorMessageFormatted(in), FfsXmlError::WARNING);
+ getErrorMessageFormatted(in.getErrorsAs<std::wstring>()), FfsXmlError::WARNING);
+
+ //(try to) migrate old configuration if needed
+ needMigration = needsMigration(doc, currentXmlFormatVer);
}
}
-void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlGuiConfig& config)
+void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlGuiConfig& cfg)
+{
+ bool needMigration = false;
+ ::readConfig(filename, XML_TYPE_GUI, cfg, XML_FORMAT_VER_FFS_GUI, needMigration); //throw FfsXmlError
+
+ if (needMigration) //(try to) migrate old configuration
+ try { xmlAccess::writeConfig(cfg, filename); /*throw FfsXmlError*/ }
+ catch (FfsXmlError&) { assert(false); } //don't bother user!
+}
+
+
+void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlBatchConfig& cfg)
{
- ::readConfig(filename, XML_TYPE_GUI, config);
+ bool needMigration = false;
+ ::readConfig(filename, XML_TYPE_BATCH, cfg, XML_FORMAT_VER_FFS_BATCH, needMigration); //throw FfsXmlError
+
+ if (needMigration) //(try to) migrate old configuration
+ try { xmlAccess::writeConfig(cfg, filename); /*throw FfsXmlError*/ }
+ catch (FfsXmlError&) { assert(false); } //don't bother user!
}
-void xmlAccess::readConfig(const Zstring& filename, xmlAccess::XmlBatchConfig& config)
+void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& cfg)
{
- ::readConfig(filename, XML_TYPE_BATCH, config);
+ bool needMigration = false;
+ ::readConfig(getGlobalConfigFile(), XML_TYPE_GLOBAL, cfg, XML_FORMAT_VER_GLOBAL, needMigration); //throw FfsXmlError
}
-void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
+namespace
+{
+template <class XmlCfg>
+XmlCfg parseConfig(const XmlDoc& doc, const Zstring& filename, int currentXmlFormatVer, std::unique_ptr<FfsXmlError>& warning) //nothrow
{
- ::readConfig(utfCvrtTo<Zstring>(getGlobalConfigFile()), XML_TYPE_GLOBAL, config);
+ XmlCfg cfg;
+ XmlIn in(doc);
+ ::readConfig(in, cfg);
+
+ if (in.errorsOccured())
+ {
+ if (!warning)
+ warning = make_unique<FfsXmlError>(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" +
+ getErrorMessageFormatted(in.getErrorsAs<std::wstring>()), FfsXmlError::WARNING);
+ }
+ else
+ {
+ //(try to) migrate old configuration if needed
+ if (needsMigration(doc, currentXmlFormatVer))
+ try { xmlAccess::writeConfig(cfg, filename); /*throw FfsXmlError*/ }
+ catch (FfsXmlError&) { assert(false); } //don't bother user!
+ }
+ return cfg;
+}
}
+void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config) //throw FfsXmlError
+{
+ assert(!filenames.empty());
+
+ std::vector<zen::MainConfiguration> mainCfgs;
+ std::unique_ptr<FfsXmlError> warning;
+
+ for (auto it = filenames.begin(); it != filenames.end(); ++it)
+ {
+ const Zstring& filename = *it;
+ const bool firstItem = it == filenames.begin(); //init all non-"mainCfg" settings with first config file
+
+ XmlDoc doc;
+ loadXmlDocument(filename, doc); //throw FfsXmlError
+ //do NOT use zen::loadStream as it will superfluously load even huge files!
+
+ switch (::getXmlType(doc))
+ {
+ case XML_TYPE_GUI:
+ {
+ XmlGuiConfig guiCfg = parseConfig<XmlGuiConfig>(doc, filename, XML_FORMAT_VER_FFS_GUI, warning); //nothrow
+ if (firstItem)
+ config = guiCfg;
+ else
+ mainCfgs.push_back(guiCfg.mainCfg);
+ }
+ break;
+
+ case XML_TYPE_BATCH:
+ {
+ XmlBatchConfig batchCfg = parseConfig<XmlBatchConfig>(doc, filename, XML_FORMAT_VER_FFS_BATCH, warning); //nothrow
+ if (firstItem)
+ config = convertBatchToGui(batchCfg);
+ else
+ mainCfgs.push_back(batchCfg.mainCfg);
+ }
+ break;
+
+ case XML_TYPE_GLOBAL:
+ case XML_TYPE_OTHER:
+ throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
+ }
+ }
+ mainCfgs.push_back(config.mainCfg); //save cfg from first line
+
+ config.mainCfg = merge(mainCfgs);
+
+ if (warning)
+ throw* warning;
+}
+
//################################################################################################
+
namespace
{
void writeConfig(const CompConfig& cmpConfig, XmlOut& out)
@@ -1188,8 +1286,8 @@ void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
void writeConfig(const FilterConfig& filter, XmlOut& out)
{
- out["Include"](filter.includeFilter);
- out["Exclude"](filter.excludeFilter);
+ out["Include"](splitFilterByLines(filter.includeFilter));
+ out["Exclude"](splitFilterByLines(filter.excludeFilter));
out["TimeSpan"](filter.timeSpan);
out["TimeSpan"].attribute("Type", filter.unitTimeSpan);
@@ -1300,31 +1398,29 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
{
XmlOut outShared = out["Shared"];
- //write program language setting
- outShared["Language"](config.programLanguage);
+ outShared["Language"].attribute("id", config.programLanguage);
- outShared["CopyLockedFiles" ](config.copyLockedFiles);
- outShared["CopyFilePermissions" ](config.copyFilePermissions);
- outShared["TransactionalFileCopy"](config.transactionalFileCopy);
- outShared["LockDirectoriesDuringSync"](config.createLockFile);
- outShared["VerifyCopiedFiles" ](config.verifyFileCopy);
- outShared["RunWithBackgroundPriority"](config.runWithBackgroundPriority);
-
- //max. allowed file time deviation
- outShared["FileTimeTolerance"](config.fileTimeTolerance);
-
- outShared["LastSyncsFileSizeMax"](config.lastSyncsLogFileSizeMax);
+ outShared["FailSafeFileCopy" ].attribute("Enabled", config.transactionalFileCopy);
+ outShared["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles);
+ outShared["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions);
+ outShared["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority);
+ outShared["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile);
+ outShared["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy);
+ outShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance);
+ outShared["LastSyncsLogSizeMax" ].attribute("Bytes" , config.lastSyncsLogFileSizeMax);
XmlOut outOpt = outShared["OptionalDialogs"];
- outOpt["WarnUnresolvedConflicts" ](config.optDialogs.warningUnresolvedConflicts);
- outOpt["WarnNotEnoughDiskSpace" ](config.optDialogs.warningNotEnoughDiskSpace);
- outOpt["WarnSignificantDifference" ](config.optDialogs.warningSignificantDifference);
- outOpt["WarnRecycleBinNotAvailable" ](config.optDialogs.warningRecyclerMissing);
- outOpt["WarnDatabaseError" ](config.optDialogs.warningDatabaseError);
- outOpt["WarnDependentFolders" ](config.optDialogs.warningDependentFolders);
- outOpt["WarnFolderPairRaceCondition"](config.optDialogs.warningFolderPairRaceCondition);
- outOpt["PromptSaveConfig" ](config.optDialogs.popupOnConfigChange);
- outOpt["ConfirmSyncStart" ](config.optDialogs.confirmSyncStart);
+ outOpt["WarnUnresolvedConflicts" ].attribute("Enabled", config.optDialogs.warningUnresolvedConflicts);
+ outOpt["WarnNotEnoughDiskSpace" ].attribute("Enabled", config.optDialogs.warningNotEnoughDiskSpace);
+ outOpt["WarnSignificantDifference" ].attribute("Enabled", config.optDialogs.warningSignificantDifference);
+ outOpt["WarnRecycleBinNotAvailable" ].attribute("Enabled", config.optDialogs.warningRecyclerMissing);
+ outOpt["WarnInputFieldEmpty" ].attribute("Enabled", config.optDialogs.warningInputFieldEmpty);
+ outOpt["WarnDatabaseError" ].attribute("Enabled", config.optDialogs.warningDatabaseError);
+ outOpt["WarnDependentFolders" ].attribute("Enabled", config.optDialogs.warningDependentFolders);
+ outOpt["WarnFolderPairRaceCondition"].attribute("Enabled", config.optDialogs.warningFolderPairRaceCondition);
+ outOpt["WarnDirectoryLockFailed" ].attribute("Enabled", config.optDialogs.warningDirectoryLockFailed);
+ outOpt["ConfirmSaveConfig" ].attribute("Enabled", config.optDialogs.popupOnConfigChange);
+ outOpt["ConfirmStartSync" ].attribute("Enabled", config.optDialogs.confirmSyncStart);
//gui specific global settings (optional)
XmlOut outGui = out["Gui"];
@@ -1341,18 +1437,20 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
//outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
outManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
- outWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
- outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
+ outWnd["CaseSensitiveSearch"].attribute("Enabled", config.gui.textSearchRespectCase);
+ outWnd["FolderPairsVisible" ].attribute("Max", config.gui.maxFolderPairsVisible);
//###########################################################
+
+ XmlOut outOverview = outWnd["OverviewPanel"];
+ outOverview.attribute("ShowPercentage", config.gui.showPercentBar);
+ outOverview.attribute("SortByColumn", config.gui.naviLastSortColumn);
+ outOverview.attribute("SortAscending", config.gui.naviLastSortAscending);
+
//write column attributes
- XmlOut outColNavi = outWnd["OverviewColumns"];
+ XmlOut outColNavi = outOverview["Columns"];
outColNavi(config.gui.columnAttribNavi);
- outColNavi.attribute("ShowPercentage", config.gui.showPercentBar);
- outColNavi.attribute("SortByColumn", config.gui.naviLastSortColumn);
- outColNavi.attribute("SortAscending", config.gui.naviLastSortAscending);
-
XmlOut outMainGrid = outWnd["MainGrid"];
outMainGrid.attribute("ShowIcons", config.gui.showIcons);
outMainGrid.attribute("IconSize", config.gui.iconSize);
@@ -1366,7 +1464,9 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
//###########################################################
outWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
- outWnd["Layout" ](config.gui.guiPerspectiveLast);
+ outWnd["Perspective" ](config.gui.guiPerspectiveLast);
+
+ outGui["DefaultExclusionFilter"](splitFilterByLines(config.gui.defaultExclusionFilter));
//load config file history
outGui["LastUsedConfig"](config.gui.lastUsedConfigFiles);
@@ -1392,11 +1492,13 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
template <class ConfigType>
-void writeConfig(const ConfigType& config, XmlType type, const Zstring& filename)
+void writeConfig(const ConfigType& config, XmlType type, int xmlFormatVer, const Zstring& filename)
{
XmlDoc doc("FreeFileSync");
setXmlType(doc, type); //throw()
+ doc.root().setAttribute("XmlFormat", xmlFormatVer);
+
XmlOut out(doc);
writeConfig(config, out);
@@ -1404,21 +1506,21 @@ void writeConfig(const ConfigType& config, XmlType type, const Zstring& filename
}
}
-void xmlAccess::writeConfig(const XmlGuiConfig& config, const Zstring& filename)
+void xmlAccess::writeConfig(const XmlGuiConfig& cfg, const Zstring& filename)
{
- ::writeConfig(config, XML_TYPE_GUI, filename); //throw FfsXmlError
+ ::writeConfig(cfg, XML_TYPE_GUI, XML_FORMAT_VER_FFS_GUI, filename); //throw FfsXmlError
}
-void xmlAccess::writeConfig(const XmlBatchConfig& config, const Zstring& filename)
+void xmlAccess::writeConfig(const XmlBatchConfig& cfg, const Zstring& filename)
{
- ::writeConfig(config, XML_TYPE_BATCH, filename); //throw FfsXmlError
+ ::writeConfig(cfg, XML_TYPE_BATCH, XML_FORMAT_VER_FFS_BATCH, filename); //throw FfsXmlError
}
-void xmlAccess::writeConfig(const XmlGlobalSettings& config)
+void xmlAccess::writeConfig(const XmlGlobalSettings& cfg)
{
- ::writeConfig(config, XML_TYPE_GLOBAL, utfCvrtTo<Zstring>(getGlobalConfigFile())); //throw FfsXmlError
+ ::writeConfig(cfg, XML_TYPE_GLOBAL, XML_FORMAT_VER_GLOBAL, getGlobalConfigFile()); //throw FfsXmlError
}
bgstack15