summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:11:56 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:11:56 +0200
commit98ecf620f7de377dc8ae9ad7fbd1e3b24477e138 (patch)
treefaadc6d8822c20cd3bc6f50b2a98e6c580585949 /library
parent3.16 (diff)
downloadFreeFileSync-98ecf620f7de377dc8ae9ad7fbd1e3b24477e138.tar.gz
FreeFileSync-98ecf620f7de377dc8ae9ad7fbd1e3b24477e138.tar.bz2
FreeFileSync-98ecf620f7de377dc8ae9ad7fbd1e3b24477e138.zip
3.17
Diffstat (limited to 'library')
-rw-r--r--library/binary.cpp6
-rw-r--r--library/binary.h6
-rw-r--r--library/cmp_filetime.h16
-rw-r--r--library/custom_grid.cpp35
-rw-r--r--library/custom_grid.h26
-rw-r--r--library/db_file.cpp259
-rw-r--r--library/db_file.h11
-rw-r--r--library/detect_renaming.h4
-rw-r--r--library/dir_lock.cpp69
-rw-r--r--library/dir_lock.h3
-rw-r--r--library/error_log.cpp4
-rw-r--r--library/error_log.h2
-rw-r--r--library/hard_filter.cpp (renamed from library/filter.cpp)96
-rw-r--r--library/hard_filter.h (renamed from library/filter.h)81
-rw-r--r--library/icon_buffer.cpp364
-rw-r--r--library/icon_buffer.h41
-rw-r--r--library/lock_holder.h52
-rw-r--r--library/norm_filter.h98
-rw-r--r--library/process_xml.cpp820
-rw-r--r--library/process_xml.h44
-rw-r--r--library/resources.cpp4
-rw-r--r--library/soft_filter.cpp10
-rw-r--r--library/soft_filter.h104
-rw-r--r--library/statistics.cpp67
-rw-r--r--library/status_handler.cpp4
-rw-r--r--library/status_handler.h69
26 files changed, 1386 insertions, 909 deletions
diff --git a/library/binary.cpp b/library/binary.cpp
index 72fc220a..3a202711 100644
--- a/library/binary.cpp
+++ b/library/binary.cpp
@@ -8,7 +8,7 @@
#include "../shared/file_io.h"
#include <vector>
#include <wx/stopwatch.h>
-
+#include "../shared/int64.h"
inline
void setMinSize(std::vector<char>& buffer, size_t minSize)
@@ -66,7 +66,7 @@ private:
}
-bool ffs3::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback)
+bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback)
{
FileInput file1(filename1); //throw (FileError)
FileInput file2(filename2); //throw (FileError)
@@ -76,7 +76,7 @@ bool ffs3::filesHaveSameContent(const Zstring& filename1, const Zstring& filenam
static std::vector<char> memory1;
static std::vector<char> memory2;
- wxLongLong bytesCompared;
+ zen::UInt64 bytesCompared;
wxLongLong lastDelayViolation = wxGetLocalTimeMillis();
diff --git a/library/binary.h b/library/binary.h
index 847c7169..b796ddbb 100644
--- a/library/binary.h
+++ b/library/binary.h
@@ -8,10 +8,10 @@
#define BINARY_H_INCLUDED
#include "../shared/zstring.h"
-#include <wx/longlong.h>
#include "../shared/file_error.h"
+#include "../shared/int64.h"
-namespace ffs3
+namespace zen
{
//callback functionality for status updates while comparing
@@ -19,7 +19,7 @@ class CompareCallback
{
public:
virtual ~CompareCallback() {}
- virtual void updateCompareStatus(const wxLongLong& totalBytesTransferred) = 0;
+ virtual void updateCompareStatus(zen::UInt64 totalBytesTransferred) = 0;
};
bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError
diff --git a/library/cmp_filetime.h b/library/cmp_filetime.h
index b95eae5f..24b331c6 100644
--- a/library/cmp_filetime.h
+++ b/library/cmp_filetime.h
@@ -1,28 +1,26 @@
#ifndef CMP_FILETIME_H_INCLUDED
#define CMP_FILETIME_H_INCLUDED
-#include <wx/longlong.h>
#include <wx/stopwatch.h>
+#include "../shared/int64.h"
-
-namespace ffs3
+namespace zen
{
//---------------------------------------------------------------------------------------------------------------
inline
-bool sameFileTime(const wxLongLong& a, const wxLongLong& b, size_t tolerance)
+bool sameFileTime(const Int64& a, const Int64& b, size_t tolerance)
{
if (a < b)
- return b <= a + tolerance;
+ return b <= a + static_cast<int>(tolerance);
else
- return a <= b + tolerance;
+ return a <= b + static_cast<int>(tolerance);
}
//---------------------------------------------------------------------------------------------------------------
class CmpFileTime
{
public:
- CmpFileTime(size_t tolerance) :
- tolerance_(tolerance) {}
+ CmpFileTime(size_t tolerance) : tolerance_(tolerance) {}
enum Result
{
@@ -33,7 +31,7 @@ public:
TIME_RIGHT_INVALID
};
- Result getResult(const wxLongLong& lhs, const wxLongLong& rhs) const
+ Result getResult(const Int64& lhs, const Int64& rhs) const
{
if (lhs == rhs)
return TIME_EQUAL;
diff --git a/library/custom_grid.cpp b/library/custom_grid.cpp
index d8ced2a3..172ad2e1 100644
--- a/library/custom_grid.cpp
+++ b/library/custom_grid.cpp
@@ -21,6 +21,7 @@
#include <wx/icon.h>
#include <wx/tooltip.h>
#include <wx/settings.h>
+#include "../shared/i18n.h"
#ifdef FFS_WIN
#include <wx/timer.h>
@@ -31,7 +32,7 @@
#include <gtk/gtk.h>
#endif
-using namespace ffs3;
+using namespace zen;
const size_t MIN_ROW_COUNT = 15;
@@ -294,10 +295,10 @@ protected:
value = zToWx(fileObj.getBaseDirPf<side>());
break;
case xmlAccess::SIZE: //file size
- value = ffs3::numberToStringSep(fileObj.getFileSize<side>());
+ value = zen::toStringSep(fileObj.getFileSize<side>());
break;
case xmlAccess::DATE: //date
- value = ffs3::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
+ value = zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
break;
case xmlAccess::EXTENSION: //file extension
value = zToWx(fileObj.getExtension<side>());
@@ -325,7 +326,7 @@ protected:
value = _("<Symlink>");
break;
case xmlAccess::DATE: //date
- value = ffs3::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
+ value = zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
break;
case xmlAccess::EXTENSION: //file extension
value = wxEmptyString;
@@ -675,7 +676,7 @@ void CustomGrid::initSettings(CustomGridLeft* gridLeft,
}
-void CustomGrid::release() //release connection to ffs3::GridView
+void CustomGrid::release() //release connection to zen::GridView
{
assert(getGridDataTable());
getGridDataTable()->setGridDataTable(NULL); //kind of "disable" griddatatable; don't delete it with SetTable(NULL)! May be used by wxGridCellStringRenderer
@@ -1352,14 +1353,14 @@ void CustomGridRim::setTooltip(const wxMouseEvent& event)
virtual void visit(const FileMapping& fileObj)
{
tipMsg_ = zToWx(fileObj.getRelativeName<side>()) + wxT("\n") +
- _("Size") + wxT(": ") + ffs3::formatFilesizeToShortString(fileObj.getFileSize<side>()) + wxT("\n") +
- _("Date") + wxT(": ") + ffs3::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
+ _("Size") + wxT(": ") + zen::formatFilesizeToShortString(fileObj.getFileSize<side>()) + wxT("\n") +
+ _("Date") + wxT(": ") + zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
}
virtual void visit(const SymLinkMapping& linkObj)
{
tipMsg_ = zToWx(linkObj.getRelativeName<side>()) + wxT("\n") +
- _("Date") + wxT(": ") + ffs3::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
+ _("Date") + wxT(": ") + zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
}
virtual void visit(const DirMapping& dirObj)
@@ -1698,7 +1699,7 @@ void CustomGridRim::getIconsToBeLoaded(std::vector<Zstring>& newLoad) //loads al
if (!fileName.empty())
{
//test if they are already loaded in buffer:
- if (ffs3::IconBuffer::getInstance().requestFileIcon(fileName))
+ if (zen::IconBuffer::getInstance().requestFileIcon(fileName))
{
//exists in buffer: refresh Row
for (int k = 0; k < totalCols; ++k)
@@ -1746,7 +1747,7 @@ void IconUpdater::loadIconsAsynchronously(wxEvent& event) //loads all (not yet)
//merge vectors
newLoad.insert(newLoad.end(), iconsLeft.begin(), iconsLeft.end());
- ffs3::IconBuffer::getInstance().setWorkload(newLoad);
+ zen::IconBuffer::getInstance().setWorkload(newLoad);
//event.Skip();
}
@@ -1775,10 +1776,10 @@ bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectio
}
-void CustomGridLeft::initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+void CustomGridLeft::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView)
+ const zen::GridView* gridDataView)
{
//set underlying grid data
assert(getGridDataTable());
@@ -1823,10 +1824,10 @@ bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelecti
}
-void CustomGridRight::initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+void CustomGridRight::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView)
+ const zen::GridView* gridDataView)
{
//set underlying grid data
assert(getGridDataTable());
@@ -1921,10 +1922,10 @@ bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelect
}
-void CustomGridMiddle::initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+void CustomGridMiddle::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView)
+ const zen::GridView* gridDataView)
{
//set underlying grid data
assert(getGridDataTable());
@@ -2345,7 +2346,7 @@ void CustomGridMiddle::DrawColLabel(wxDC& dc, int col)
}
-const wxBitmap& ffs3::getSyncOpImage(SyncOperation syncOp)
+const wxBitmap& zen::getSyncOpImage(SyncOperation syncOp)
{
switch (syncOp) //evaluate comparison result and sync direction
{
diff --git a/library/custom_grid.h b/library/custom_grid.h
index e8138bfc..1301486f 100644
--- a/library/custom_grid.h
+++ b/library/custom_grid.h
@@ -30,7 +30,7 @@ class CustomGridMiddle;
class CustomGridRight;
-namespace ffs3
+namespace zen
{
class GridView;
@@ -63,12 +63,12 @@ public:
virtual ~CustomGrid() {}
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+ virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView);
+ const zen::GridView* gridDataView);
- void release(); //release connection to ffs3::GridView
+ void release(); //release connection to zen::GridView
std::set<size_t> getAllSelectedRows() const;
@@ -165,7 +165,7 @@ public:
void enableFileIcons(const bool value);
protected:
- template <ffs3::SelectedSide side>
+ template <zen::SelectedSide side>
void setTooltip(const wxMouseEvent& event);
void setOtherGrid(CustomGridRim* other); //call during initialization!
@@ -211,10 +211,10 @@ public:
virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+ virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView);
+ const zen::GridView* gridDataView);
private:
void OnMouseMovement(wxMouseEvent& event);
@@ -234,10 +234,10 @@ public:
virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+ virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView);
+ const zen::GridView* gridDataView);
private:
void OnMouseMovement(wxMouseEvent& event);
@@ -261,10 +261,10 @@ public:
virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with ffs3::GridView
+ virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
- const ffs3::GridView* gridDataView);
+ const zen::GridView* gridDataView);
void enableSyncPreview(bool value);
@@ -346,7 +346,7 @@ extern const wxEventType FFS_SYNC_DIRECTION_EVENT; //define new event type
class FFSSyncDirectionEvent : public wxCommandEvent
{
public:
- FFSSyncDirectionEvent(const int from, const int to, const ffs3::SyncDirection dir) :
+ FFSSyncDirectionEvent(const int from, const int to, const zen::SyncDirection dir) :
wxCommandEvent(FFS_SYNC_DIRECTION_EVENT),
rowFrom(from),
rowTo(to),
@@ -359,7 +359,7 @@ public:
const int rowFrom;
const int rowTo;
- const ffs3::SyncDirection direction;
+ const zen::SyncDirection direction;
};
typedef void (wxEvtHandler::*FFSSyncDirectionEventFunction)(FFSSyncDirectionEvent&);
diff --git a/library/db_file.cpp b/library/db_file.cpp
index 43ebf283..47e03b66 100644
--- a/library/db_file.cpp
+++ b/library/db_file.cpp
@@ -7,29 +7,30 @@
#include "db_file.h"
#include <wx/wfstream.h>
#include <wx/zstream.h>
+#include <wx/mstream.h>
#include "../shared/global_func.h"
#include "../shared/file_error.h"
#include "../shared/string_conv.h"
#include "../shared/file_handling.h"
-#include <wx/mstream.h>
#include "../shared/serialize.h"
#include "../shared/file_io.h"
#include "../shared/loki/ScopeGuard.h"
#include "../shared/i18n.h"
+#include <boost/bind.hpp>
#ifdef FFS_WIN
#include <wx/msw/wrapwin.h> //includes "windows.h"
#include "../shared/long_path_prefix.h"
#endif
-using namespace ffs3;
+using namespace zen;
namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 5;
+const int FILE_FORMAT_VER = 6;
//-------------------------------------------------------------------------------------------------------------------------------
@@ -67,19 +68,17 @@ private:
//#######################################################################################################################################
-
-
-class ReadDirInfo : public util::ReadInputStream
+class ReadDirInfo : public zen::ReadInputStream
{
public:
ReadDirInfo(wxInputStream& stream, const wxString& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName)
{
//|-------------------------------------------------------------------------------------
- //| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t |
+ //| ensure 32/64 bit portability: use fixed size data types only e.g. boost::uint32_t |
//|-------------------------------------------------------------------------------------
- //read filter settings
- dirInfo.filter = BaseFilter::loadFilter(getStream());
+ //read filter settings -> currently not required, but persisting it doesn't hurt
+ dirInfo.filter = HardFilter::loadFilter(getStream());
check();
//start recursion
@@ -89,56 +88,48 @@ public:
private:
void execute(DirContainer& dirCont) const
{
- boost::uint32_t fileCount = readNumberC<boost::uint32_t>();
- while (fileCount-- != 0)
+ while (readNumberC<bool>())
readSubFile(dirCont);
- boost::uint32_t symlinkCount = readNumberC<boost::uint32_t>();
- while (symlinkCount-- != 0)
+ while (readNumberC<bool>())
readSubLink(dirCont);
- boost::uint32_t dirCount = readNumberC<boost::uint32_t>();
- while (dirCount-- != 0)
+ while (readNumberC<bool>())
readSubDirectory(dirCont);
}
void readSubFile(DirContainer& dirCont) const
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC(); //file name
-
- const boost::int32_t modHigh = readNumberC<boost::int32_t>();
- const boost::uint32_t modLow = readNumberC<boost::uint32_t>();
+ const Zstring shortName = readStringC<Zstring>(); //file name
- const boost::uint32_t sizeHigh = readNumberC<boost::uint32_t>();
- const boost::uint32_t sizeLow = readNumberC<boost::uint32_t>();
+ const boost::int64_t modTime = readNumberC<boost::int64_t>();
+ const boost::uint64_t fileSize = readNumberC<boost::uint64_t>();
//const util::FileID fileIdentifier(stream_);
//check();
dirCont.addSubFile(shortName,
- FileDescriptor(wxLongLong(modHigh, modLow),
- wxULongLong(sizeHigh, sizeLow)));
+ FileDescriptor(modTime, fileSize));
}
void readSubLink(DirContainer& dirCont) const
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC(); //file name
- const boost::int32_t modHigh = readNumberC<boost::int32_t>();
- const boost::uint32_t modLow = readNumberC<boost::uint32_t>();
- const Zstring targetPath = readStringC(); //file name
+ const Zstring shortName = readStringC<Zstring>(); //file name
+ const boost::int64_t modTime = readNumberC<boost::int64_t>();
+ const Zstring targetPath = readStringC<Zstring>(); //file name
const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readNumberC<boost::int32_t>());
dirCont.addSubLink(shortName,
- LinkDescriptor(wxLongLong(modHigh, modLow), targetPath, linkType));
+ LinkDescriptor(modTime, targetPath, linkType));
}
void readSubDirectory(DirContainer& dirCont) const
{
- const Zstring shortName = readStringC(); //directory name
+ const Zstring shortName = readStringC<Zstring>(); //directory name
DirContainer& subDir = dirCont.addSubDir(shortName);
execute(subDir); //recurse
}
@@ -161,17 +152,19 @@ Partner-ID 567 _/ \_ Partner-ID 123
... ...
*/
-class ReadFileStream : public util::ReadInputStream
+class ReadFileStream : public zen::ReadInputStream
{
public:
- ReadFileStream(wxInputStream& stream, const wxString& filename, DbStreamData& output) : ReadInputStream(stream, filename)
+ ReadFileStream(wxInputStream& stream, const wxString& filename, DbStreamData& output, int& versionId) : ReadInputStream(stream, filename)
{
//|-------------------------------------------------------------------------------------
//| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t |
//|-------------------------------------------------------------------------------------
- if (readNumberC<boost::int32_t>() != FILE_FORMAT_VER) //read file format version
+ boost::int32_t version = readNumberC<boost::int32_t>();
+ if (version != FILE_FORMAT_VER) //read file format version
throw FileError(wxString(_("Incompatible synchronization database format:")) + wxT(" \n") + wxT("\"") + filename + wxT("\""));
+ versionId = version;
//read DB id
const CharArray tmp = readArrayC();
@@ -197,7 +190,7 @@ public:
DbStreamData loadFile(const Zstring& filename) //throw (FileError)
{
- if (!ffs3::fileExists(filename))
+ if (!zen::fileExists(filename))
throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
_("One of the FreeFileSync database files is not yet existing:") + wxT(" \n") +
wxT("\"") + zToWx(filename) + wxT("\""));
@@ -208,12 +201,13 @@ DbStreamData loadFile(const Zstring& filename) //throw (FileError)
wxZlibInputStream input(uncompressed, wxZLIB_ZLIB);
DbStreamData output;
- ReadFileStream(input, zToWx(filename), output);
+ int versionId = 0;
+ ReadFileStream (input, zToWx(filename), output, versionId);
return output;
}
-std::pair<DirInfoPtr, DirInfoPtr> ffs3::loadFromDisk(const BaseDirMapping& baseMapping) //throw (FileError)
+std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw (FileError)
{
const Zstring fileNameLeft = baseMapping.getDBFilename<LEFT_SIDE>();
const Zstring fileNameRight = baseMapping.getDBFilename<RIGHT_SIDE>();
@@ -257,87 +251,128 @@ std::pair<DirInfoPtr, DirInfoPtr> ffs3::loadFromDisk(const BaseDirMapping& baseM
//-------------------------------------------------------------------------------------------------------------------------
-
template <SelectedSide side>
-struct IsNonEmpty
-{
- bool operator()(const FileSystemObject& fsObj) const
- {
- return !fsObj.isEmpty<side>();
- }
-};
-
-
-template <SelectedSide side>
-class SaveDirInfo : public util::WriteOutputStream
+class SaveDirInfo : public WriteOutputStream
{
public:
- SaveDirInfo(const BaseDirMapping& baseMapping, const wxString& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream)
+ SaveDirInfo(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const wxString& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream)
{
//save filter settings
baseMapping.getFilter()->saveFilter(getStream());
check();
//start recursion
- execute(baseMapping);
+ execute(baseMapping, oldDirInfo);
}
private:
- friend class util::ProxyForEach<SaveDirInfo<side> >; //friend declaration of std::for_each is NOT sufficient as implementation is compiler dependent!
-
- void execute(const HierarchyObject& hierObj)
+ void execute(const HierarchyObject& hierObj, const DirContainer* oldDirInfo)
{
- util::ProxyForEach<SaveDirInfo<side> > prx(*this); //grant std::for_each access to private parts of this class
-
- writeNumberC<boost::uint32_t>(std::count_if(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), IsNonEmpty<side>())); //number of (existing) files
- std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), prx);
-
- writeNumberC<boost::uint32_t>(std::count_if(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), IsNonEmpty<side>())); //number of (existing) files
- std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), prx);
-
- writeNumberC<boost::uint32_t>(std::count_if(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), IsNonEmpty<side>())); //number of (existing) directories
- std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), prx);
+ std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo));
+ writeNumberC<bool>(false); //mark last entry
+ std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo));
+ writeNumberC<bool>(false); //mark last entry
+ std::for_each(hierObj.useSubDirs ().begin(), hierObj.useSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo));
+ writeNumberC<bool>(false); //mark last entry
}
- void operator()(const FileMapping& fileMap)
+ void processFile(const FileMapping& fileMap, const DirContainer* oldDirInfo)
{
- if (!fileMap.isEmpty<side>())
+ const Zstring shortName = fileMap.getObjShortName();
+
+ if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
+ {
+ if (!fileMap.isEmpty<side>())
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ writeNumberC<boost::int64_t >(to<boost::int64_t>(fileMap.getLastWriteTime<side>())); //last modification time
+ writeNumberC<boost::uint64_t>(to<boost::uint64_t>(fileMap.getFileSize<side>())); //filesize
+ }
+ }
+ else //not in sync: reuse last synchronous state
{
- writeStringC(fileMap.getShortName<side>()); //file name
- writeNumberC<boost::int32_t> (fileMap.getLastWriteTime<side>().GetHi()); //last modification time
- writeNumberC<boost::uint32_t>(fileMap.getLastWriteTime<side>().GetLo()); //
- writeNumberC<boost::uint32_t>(fileMap.getFileSize<side>().GetHi()); //filesize
- writeNumberC<boost::uint32_t>(fileMap.getFileSize<side>().GetLo()); //
-
- //fileMap.getFileID<side>().toStream(stream_); //unique file identifier
- //check();
+ if (oldDirInfo) //no data is also a "synchronous state"!
+ {
+ DirContainer::FileList::const_iterator iter = oldDirInfo->files.find(shortName);
+ if (iter != oldDirInfo->files.end())
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ writeNumberC<boost::int64_t >(to<boost::int64_t>(iter->second.lastWriteTimeRaw)); //last modification time
+ writeNumberC<boost::uint64_t>(to<boost::uint64_t>(iter->second.fileSize)); //filesize
+ }
+ }
}
}
- void operator()(const SymLinkMapping& linkObj)
+ void processLink(const SymLinkMapping& linkObj, const DirContainer* oldDirInfo)
{
- if (!linkObj.isEmpty<side>())
+ const Zstring shortName = linkObj.getObjShortName();
+
+ if (linkObj.getCategory() == FILE_EQUAL) //data in sync: write current state
+ {
+ if (!linkObj.isEmpty<side>())
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ writeNumberC<boost::int64_t>(to<boost::int64_t>(linkObj.getLastWriteTime<side>())); //last modification time
+ writeStringC(linkObj.getTargetPath<side>());
+ writeNumberC<boost::int32_t>(linkObj.getLinkType<side>());
+ }
+ }
+ else //not in sync: reuse last synchronous state
{
- writeStringC(linkObj.getShortName<side>());
- writeNumberC<boost::int32_t> (linkObj.getLastWriteTime<side>().GetHi()); //last modification time
- writeNumberC<boost::uint32_t>(linkObj.getLastWriteTime<side>().GetLo()); //
- writeStringC(linkObj.getTargetPath<side>());
- writeNumberC<boost::int32_t>(linkObj.getLinkType<side>());
+ if (oldDirInfo) //no data is also a "synchronous state"!
+ {
+ DirContainer::LinkList::const_iterator iter = oldDirInfo->links.find(shortName);
+ if (iter != oldDirInfo->links.end())
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ writeNumberC<boost::int64_t>(to<boost::int64_t>(iter->second.lastWriteTimeRaw)); //last modification time
+ writeStringC(iter->second.targetPath);
+ writeNumberC<boost::int32_t>(iter->second.type);
+ }
+ }
}
}
- void operator()(const DirMapping& dirMap)
+ void processDir(const DirMapping& dirMap, const DirContainer* oldDirInfo)
{
- if (!dirMap.isEmpty<side>())
+ const Zstring shortName = dirMap.getObjShortName();
+
+ const DirContainer* subDirInfo = NULL;
+ if (oldDirInfo) //no data is also a "synchronous state"!
+ {
+ DirContainer::DirList::const_iterator iter = oldDirInfo->dirs.find(shortName);
+ if (iter != oldDirInfo->dirs.end())
+ subDirInfo = &iter->second;
+ }
+
+ if (dirMap.getCategory() == FILE_EQUAL) //data in sync: write current state
{
- writeStringC(dirMap.getShortName<side>()); //directory name
- execute(dirMap); //recurse
+ if (!dirMap.isEmpty<side>())
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ execute(dirMap, subDirInfo); //recurse
+ }
+ }
+ else //not in sync: reuse last synchronous state
+ {
+ if (subDirInfo) //no data is also a "synchronous state"!
+ {
+ writeNumberC<bool>(true); //mark beginning of entry
+ writeStringC(shortName);
+ }
+ execute(dirMap, subDirInfo); //recurse
}
}
};
-class WriteFileStream : public util::WriteOutputStream
+class WriteFileStream : public WriteOutputStream
{
public:
WriteFileStream(const DbStreamData& input, const wxString& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream)
@@ -383,7 +418,7 @@ void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (Fi
}
//(try to) hide database file
#ifdef FFS_WIN
- ::SetFileAttributes(ffs3::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN);
+ ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN);
#endif
}
@@ -395,13 +430,13 @@ bool entryExisting(const DirectoryTOC& table, const UniqueId& newKey, const Memo
return false;
if (!newValue.get() || !iter->second.get())
- return !newValue.get() && !iter->second.get();
+ return newValue.get() == iter->second.get();
return *newValue == *iter->second;
}
-void ffs3::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
+void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
{
//transactional behaviour! write to tmp files first
const Zstring fileNameLeftTmp = baseMapping.getDBFilename<LEFT_SIDE>() + Zstr(".tmp");
@@ -437,11 +472,47 @@ void ffs3::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
dbEntriesRight.first = util::generateGUID();
}
+
+ //(try to) read old DirInfo
+ std::auto_ptr<DirInformation> oldDirInfoLeft;
+ try
+ {
+ DirectoryTOC::const_iterator iter = dbEntriesLeft.second.find(dbEntriesRight.first);
+ if (iter != dbEntriesLeft.second.end())
+ if (iter->second.get())
+ {
+ const std::vector<char>& memStream = *iter->second;
+ wxMemoryInputStream buffer(&memStream[0], memStream.size()); //convert char-array to inputstream: no copying, ownership not transferred
+ std::auto_ptr<DirInformation> dirInfoTmp(new DirInformation);
+ ReadDirInfo(buffer, zToWx(baseMapping.getDBFilename<LEFT_SIDE>()), *dirInfoTmp); //read file/dir information
+ oldDirInfoLeft = dirInfoTmp;
+ }
+ }
+ catch(FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
+
+ std::auto_ptr<DirInformation> oldDirInfoRight;
+ try
+ {
+ DirectoryTOC::const_iterator iter = dbEntriesRight.second.find(dbEntriesLeft.first);
+ if (iter != dbEntriesRight.second.end())
+ if (iter->second.get())
+ {
+ const std::vector<char>& memStream = *iter->second;
+ wxMemoryInputStream buffer(&memStream[0], memStream.size()); //convert char-array to inputstream: no copying, ownership not transferred
+ std::auto_ptr<DirInformation> dirInfoTmp(new DirInformation);
+ ReadDirInfo(buffer, zToWx(baseMapping.getDBFilename<RIGHT_SIDE>()), *dirInfoTmp); //read file/dir information
+ oldDirInfoRight = dirInfoTmp;
+ }
+ }
+ catch(FileError&) {}
+
+
//create new database entries
MemoryStreamPtr dbEntryLeft(new std::vector<char>);
{
wxMemoryOutputStream buffer;
- SaveDirInfo<LEFT_SIDE>(baseMapping, zToWx(baseMapping.getDBFilename<LEFT_SIDE>()), buffer);
+ DirContainer* oldDir = oldDirInfoLeft.get() ? &oldDirInfoLeft->baseDirContainer : NULL;
+ SaveDirInfo<LEFT_SIDE>(baseMapping, oldDir, zToWx(baseMapping.getDBFilename<LEFT_SIDE>()), buffer);
dbEntryLeft->resize(buffer.GetSize()); //convert output stream to char-array
buffer.CopyTo(&(*dbEntryLeft)[0], buffer.GetSize()); //
}
@@ -449,7 +520,8 @@ void ffs3::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
MemoryStreamPtr dbEntryRight(new std::vector<char>);
{
wxMemoryOutputStream buffer;
- SaveDirInfo<RIGHT_SIDE>(baseMapping, zToWx(baseMapping.getDBFilename<RIGHT_SIDE>()), buffer);
+ DirContainer* oldDir = oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL;
+ SaveDirInfo<RIGHT_SIDE>(baseMapping, oldDir, zToWx(baseMapping.getDBFilename<RIGHT_SIDE>()), buffer);
dbEntryRight->resize(buffer.GetSize()); //convert output stream to char-array
buffer.CopyTo(&(*dbEntryRight)[0], buffer.GetSize()); //
}
@@ -462,15 +534,14 @@ void ffs3::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
if (!updateRequiredLeft && !updateRequiredRight)
return;
}
-
- dbEntriesLeft.second[dbEntriesRight.first] = dbEntryLeft;
- dbEntriesRight.second[dbEntriesLeft.first] = dbEntryRight;
+ dbEntriesLeft .second[dbEntriesRight.first] = dbEntryLeft;
+ dbEntriesRight.second[dbEntriesLeft .first] = dbEntryRight;
//write (temp-) files...
- Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&ffs3::removeFile, fileNameLeftTmp);
+ Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&zen::removeFile, fileNameLeftTmp);
saveFile(dbEntriesLeft, fileNameLeftTmp); //throw (FileError)
- Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&ffs3::removeFile, fileNameRightTmp);
+ Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&zen::removeFile, fileNameRightTmp);
saveFile(dbEntriesRight, fileNameRightTmp); //throw (FileError)
//operation finished: rename temp files -> this should work transactionally:
diff --git a/library/db_file.h b/library/db_file.h
index 8b88473d..179ebd57 100644
--- a/library/db_file.h
+++ b/library/db_file.h
@@ -7,24 +7,21 @@
#ifndef DBFILE_H_INCLUDED
#define DBFILE_H_INCLUDED
+#include "../shared/file_error.h"
#include "../file_hierarchy.h"
-namespace ffs3
+namespace zen
{
void saveToDisk(const BaseDirMapping& baseMapping); //throw (FileError)
struct DirInformation
{
- BaseFilter::FilterRef filter; //filter settings (used when retrieving directory data)
+ HardFilter::FilterRef filter; //filter settings (used when retrieving directory data)
DirContainer baseDirContainer; //hierarchical directory information
};
typedef boost::shared_ptr<const DirInformation> DirInfoPtr;
-class FileErrorDatabaseNotExisting : public FileError
-{
-public:
- FileErrorDatabaseNotExisting(const wxString& message) : FileError(message) {}
-};
+DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting);
std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw (FileError, FileErrorDatabaseNotExisting) -> return value always bound!
}
diff --git a/library/detect_renaming.h b/library/detect_renaming.h
index ab974cf9..9f360f8e 100644
--- a/library/detect_renaming.h
+++ b/library/detect_renaming.h
@@ -12,13 +12,13 @@
//identify a file "create and delete"-operation as a file renaming!
-namespace ffs3
+namespace zen
{
typedef FileMapping* CreateOnLeft;
typedef FileMapping* DeleteOnLeft;
typedef FileMapping* CreateOnRight;
typedef FileMapping* DeleteOnRight;
-void getRenameCandidates(ffs3::BaseDirMapping& baseMapping, //in
+void getRenameCandidates(zen::BaseDirMapping& baseMapping, //in
std::vector<std::pair<CreateOnLeft, DeleteOnLeft> >& renameOnLeft, //out
std::vector<std::pair<CreateOnRight, DeleteOnRight> >& renameOnRight); //out throw()!
}
diff --git a/library/dir_lock.cpp b/library/dir_lock.cpp
index 521f1c6f..8b9032b4 100644
--- a/library/dir_lock.cpp
+++ b/library/dir_lock.cpp
@@ -4,12 +4,11 @@
#include <wx/timer.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
-#include <boost/cstdint.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include "../shared/string_conv.h"
#include "../shared/i18n.h"
-#include "../shared/system_func.h"
+#include "../shared/last_error.h"
#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
#include "../shared/loki/ScopeGuard.h"
#include "../shared/system_constants.h"
@@ -18,6 +17,7 @@
#include "../shared/assert_static.h"
#include "../shared/serialize.h"
#include "../shared/build_info.h"
+#include "../shared/int64.h"
#ifdef FFS_WIN
#include <tlhelp32.h>
@@ -31,7 +31,7 @@
#include <unistd.h>
#endif
-using namespace ffs3;
+using namespace zen;
using namespace std::rel_ops;
@@ -153,16 +153,18 @@ void deleteLockFile(const Zstring& filename) //throw (FileError)
}
-wxULongLong getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNotExisting)
+zen::UInt64 getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNotExisting)
{
#ifdef FFS_WIN
- WIN32_FIND_DATA fileMetaData;
- const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileMetaData);
+ WIN32_FIND_DATA fileInfo = {};
+ const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
if (searchHandle == INVALID_HANDLE_VALUE)
{
const DWORD lastError = ::GetLastError();
- const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"") +
- wxT("\n\n") + getLastErrorFormatted(lastError);
+
+ wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"");
+ errorMessage += wxT("\n\n") + getLastErrorFormatted(lastError);
+
if (lastError == ERROR_FILE_NOT_FOUND ||
lastError == ERROR_PATH_NOT_FOUND)
throw ErrorNotExisting(errorMessage);
@@ -172,22 +174,24 @@ wxULongLong getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo
::FindClose(searchHandle);
- return wxULongLong(fileMetaData.nFileSizeHigh, fileMetaData.nFileSizeLow);
+ return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
#elif defined FFS_LINUX
- struct stat fileInfo;
+ struct stat fileInfo = {};
if (::stat(filename.c_str(), &fileInfo) != 0) //follow symbolic links
{
const int lastError = errno;
- const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"") +
- wxT("\n\n") + getLastErrorFormatted(lastError);
+
+ wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"");
+ errorMessage += wxT("\n\n") + getLastErrorFormatted(lastError);
+
if (lastError == ENOENT)
throw ErrorNotExisting(errorMessage);
else
throw FileError(errorMessage);
}
- return fileInfo.st_size;
+ return zen::UInt64(fileInfo.st_size);
#endif
}
@@ -208,7 +212,7 @@ namespace
inline
std::string readString(wxInputStream& stream) //throw (std::exception)
{
- const boost::uint32_t strLength = util::readNumber<boost::uint32_t>(stream);
+ const boost::uint32_t strLength = readPOD<boost::uint32_t>(stream);
std::string output;
if (strLength > 0)
{
@@ -223,7 +227,7 @@ inline
void writeString(wxOutputStream& stream, const std::string& str) //write string to filestream
{
const boost::uint32_t strLength = static_cast<boost::uint32_t>(str.length());
- util::writeNumber<boost::uint32_t>(stream, strLength);
+ writePOD<boost::uint32_t>(stream, strLength);
stream.Write(str.c_str(), strLength);
}
@@ -257,13 +261,13 @@ struct LockInformation
{
char formatDescr[sizeof(LOCK_FORMAT_DESCR)] = {};
stream.Read(formatDescr, sizeof(LOCK_FORMAT_DESCR)); //file format header
- const int lockFileVersion = util::readNumber<boost::int32_t>(stream); //
+ const int lockFileVersion = readPOD<boost::int32_t>(stream); //
(void)lockFileVersion;
//some format checking here?
lockId = readString(stream);
- procDescr.processId = static_cast<ProcessId>(util::readNumber<boost::uint64_t>(stream)); //possible loss of precision (32/64 bit process) covered by buildId
+ procDescr.processId = static_cast<ProcessId>(readPOD<boost::uint64_t>(stream)); //possible loss of precision (32/64 bit process) covered by buildId
procDescr.computerId = readString(stream);
}
@@ -272,10 +276,10 @@ struct LockInformation
assert_static(sizeof(ProcessId) <= sizeof(boost::uint64_t)); //ensure portability
stream.Write(LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
- util::writeNumber<boost::int32_t>(stream, LOCK_FORMAT_VER);
+ writePOD<boost::int32_t>(stream, LOCK_FORMAT_VER);
writeString(stream, lockId);
- util::writeNumber<boost::uint64_t>(stream, procDescr.processId);
+ writePOD<boost::uint64_t>(stream, procDescr.processId);
writeString(stream, procDescr.computerId);
}
@@ -337,7 +341,7 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
if (procDescr.processId <= 0 || procDescr.processId >= 65536)
return PROC_STATUS_NO_IDEA; //invalid process id
- return ffs3::dirExists(Zstr("/proc/") + Zstring::fromNumber(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
+ return zen::dirExists(Zstr("/proc/") + Zstring::fromNumber(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
#endif
}
@@ -377,13 +381,13 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr
const LockInformation lockInfo = retrieveLockInfo(lockfilename); //throw (FileError, ErrorNotExisting)
const bool lockOwnderDead = getProcessStatus(lockInfo.procDescr) == PROC_STATUS_NOT_RUNNING; //convenience optimization: if we know the owning process crashed, we needn't wait DETECT_EXITUS_INTERVAL sec
- wxULongLong fileSizeOld;
+ zen::UInt64 fileSizeOld;
wxLongLong lockSilentStart = wxGetLocalTimeMillis();
while (true)
{
- const wxULongLong fileSizeNew = ::getLockFileSize(lockfilename); //throw (FileError, ErrorNotExisting)
- const wxLongLong currentTime = wxGetLocalTimeMillis();
+ const zen::UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw (FileError, ErrorNotExisting)
+ wxLongLong currentTime = wxGetLocalTimeMillis();
if (fileSizeNew != fileSizeOld)
{
@@ -421,10 +425,10 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr
{
if (currentTime - lockSilentStart > EMIT_LIFE_SIGN_INTERVAL) //one signal missed: it's likely this is an abandoned lock:
{
- long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).GetLo();
- remainingSeconds = std::max(0L, remainingSeconds);
+ long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong();
+ remainingSeconds = std::max(0L, remainingSeconds);
- Zstring remSecMsg = wxToZ(_("%x sec"));
+ Zstring remSecMsg = wxToZ(_P("1 sec", "%x sec", remainingSeconds));
remSecMsg.Replace(Zstr("%x"), Zstring::fromNumber(remainingSeconds));
callback->reportInfo(infoMsg + Zstr(" ") + remSecMsg);
}
@@ -467,8 +471,10 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError)
if (::GetLastError() == ERROR_FILE_EXISTS)
return false;
else
- throw FileError(wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"") +
- wxT("\n\n") + getLastErrorFormatted());
+ {
+ wxString errorMessage = wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + getLastErrorFormatted());
+ }
}
::CloseHandle(fileHandle);
@@ -481,8 +487,11 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError)
if (errno == EEXIST)
return false;
else
- throw FileError(wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"") +
- wxT("\n\n") + getLastErrorFormatted());
+ {
+ wxString errorMessage = wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + getLastErrorFormatted());
+ }
+
}
::close(fileHandle);
#endif
diff --git a/library/dir_lock.h b/library/dir_lock.h
index 9ae4da08..91b61990 100644
--- a/library/dir_lock.h
+++ b/library/dir_lock.h
@@ -19,12 +19,13 @@ RAII structure to place a directory lock against other FFS processes:
- ownership shared between all object instances refering to a specific lock location(= UUID)
- can be copied safely and efficiently! (ref-counting)
- detects and resolves abandoned locks (instantly if lock is associated with local pc, else after 30 seconds)
+ - temporary locks created during abandoned lock resolution keep "lockfilename"'s extension
- race-free (Windows, almost on Linux(NFS))
*/
class DirLock
{
public:
- DirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL); //throw (FileError)
+ DirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL); //throw (FileError), callback only used during construction
private:
class LockAdmin;
diff --git a/library/error_log.cpp b/library/error_log.cpp
index 483d670b..a78b1c9a 100644
--- a/library/error_log.cpp
+++ b/library/error_log.cpp
@@ -9,10 +9,10 @@
#include "../shared/i18n.h"
-using ffs3::ErrorLogging;
+using zen::ErrorLogging;
-void ErrorLogging::logMsg(const wxString& message, ffs3::MessageType type)
+void ErrorLogging::logMsg(const wxString& message, zen::MessageType type)
{
Entry newEntry;
newEntry.type = type;
diff --git a/library/error_log.h b/library/error_log.h
index ff4d3aee..1acc0f8c 100644
--- a/library/error_log.h
+++ b/library/error_log.h
@@ -13,7 +13,7 @@
#include "../shared/zstring.h"
-namespace ffs3
+namespace zen
{
enum MessageType
{
diff --git a/library/filter.cpp b/library/hard_filter.cpp
index 70933b13..46ccc9ca 100644
--- a/library/filter.cpp
+++ b/library/hard_filter.cpp
@@ -4,7 +4,7 @@
// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
// **************************************************************************
//
-#include "filter.h"
+#include "hard_filter.h"
#include "../shared/zstring.h"
#include <wx/string.h>
#include <set>
@@ -16,47 +16,34 @@
#include "../shared/loki/LokiTypeInfo.h"
#include "../shared/serialize.h"
-using ffs3::BaseFilter;
-using ffs3::NameFilter;
+using namespace zen;
//--------------------------------------------------------------------------------------------------
-bool BaseFilter::operator==(const BaseFilter& other) const
+bool zen::operator<(const HardFilter& lhs, const HardFilter& rhs)
{
- return !(*this < other) && !(other < *this);
-}
-
-
-bool BaseFilter::operator!=(const BaseFilter& other) const
-{
- return !(*this == other);
-}
-
-
-bool BaseFilter::operator<(const BaseFilter& other) const
-{
- if (Loki::TypeInfo(typeid(*this)) != typeid(other))
- return Loki::TypeInfo(typeid(*this)) < typeid(other);
+ if (Loki::TypeInfo(typeid(lhs)) != typeid(rhs))
+ return Loki::TypeInfo(typeid(lhs)) < typeid(rhs);
//this and other are same type:
- return cmpLessSameType(other);
+ return lhs.cmpLessSameType(rhs);
}
-void BaseFilter::saveFilter(wxOutputStream& stream) const //serialize derived object
+void HardFilter::saveFilter(wxOutputStream& stream) const //serialize derived object
{
//save type information
- util::writeString(stream, uniqueClassIdentifier());
+ writeString(stream, uniqueClassIdentifier());
//save actual object
save(stream);
}
-BaseFilter::FilterRef BaseFilter::loadFilter(wxInputStream& stream)
+HardFilter::FilterRef HardFilter::loadFilter(wxInputStream& stream)
{
//read type information
- const Zstring uniqueClassId = util::readString(stream);
+ const Zstring uniqueClassId = readString<Zstring>(stream);
//read actual object
if (uniqueClassId == Zstr("NullFilter"))
@@ -83,10 +70,10 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st
//Linux DOES distinguish between upper/lower-case: nothing to do here
#endif
- static const Zstring sepAsterisk = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('*');
- static const Zstring sepQuestionMark = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('?');
- static const Zstring asteriskSep = Zstring(Zchar('*')) + common::FILE_NAME_SEPARATOR;
- static const Zstring questionMarkSep = Zstring(Zchar('?')) + common::FILE_NAME_SEPARATOR;
+ const Zstring sepAsterisk = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('*');
+ const Zstring sepQuestionMark = Zstring(common::FILE_NAME_SEPARATOR) + Zchar('?');
+ const Zstring asteriskSep = Zstring(Zstr('*')) + common::FILE_NAME_SEPARATOR;
+ const Zstring questionMarkSep = Zstring(Zstr('?')) + common::FILE_NAME_SEPARATOR;
//--------------------------------------------------------------------------------------------------
//add some syntactic sugar: handle beginning of filtername
@@ -143,14 +130,14 @@ const T* cStringFind(const T* str1, T ch) //strchr()
}
-bool matchesMask(const Zchar* string, const Zchar* mask)
+bool matchesMask(const Zchar* str, const Zchar* mask)
{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++string)
+ for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
{
switch (ch)
{
case Zchar('?'):
- if (*string == 0)
+ if (*str == 0)
return false;
break;
@@ -162,34 +149,34 @@ bool matchesMask(const Zchar* string, const Zchar* mask)
ch = *mask;
}
while (ch == Zchar('*') || ch == Zchar('?'));
- //if match ends with '*':
+ //if mask ends with '*':
if (ch == 0)
return true;
++mask;
- while ((string = cStringFind(string, ch)) != NULL)
+ while ((str = cStringFind(str, ch)) != NULL)
{
- ++string;
- if (matchesMask(string, mask))
+ ++str;
+ if (matchesMask(str, mask))
return true;
}
return false;
default:
- if (*string != ch)
+ if (*str != ch)
return false;
}
}
- return *string == 0;
+ return *str == 0;
}
//returns true if string matches at least the beginning of mask
inline
-bool matchesMaskBegin(const Zchar* string, const Zchar* mask)
+bool matchesMaskBegin(const Zchar* str, const Zchar* mask)
{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++string)
+ for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
{
- if (*string == 0)
+ if (*str == 0)
return true;
switch (ch)
@@ -201,11 +188,11 @@ bool matchesMaskBegin(const Zchar* string, const Zchar* mask)
return true;
default:
- if (*string != ch)
+ if (*str != ch)
return false;
}
}
- return *string == 0;
+ return *str == 0;
}
}
@@ -244,11 +231,18 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString)
//delimiters may be ';' or '\n'
std::vector<Zstring> output;
- const std::vector<Zstring> filterPreProcessing = filterString.Split(Zchar(';'));
- for (std::vector<Zstring>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i)
+ const std::vector<Zstring> blocks = filterString.Split(Zchar(';'));
+ for (std::vector<Zstring>::const_iterator i = blocks.begin(); i != blocks.end(); ++i)
{
- const std::vector<Zstring> newEntries = i->Split(Zchar('\n'));
- output.insert(output.end(), newEntries.begin(), newEntries.end());
+ const std::vector<Zstring> blocks2 = i->Split(Zchar('\n'));
+
+ for (std::vector<Zstring>::const_iterator j = blocks2.begin(); j != blocks2.end(); ++j)
+ {
+ Zstring entry = *j;
+ entry.Trim();
+ if (!entry.empty())
+ output.push_back(entry);
+ }
}
return output;
@@ -327,7 +321,7 @@ bool NameFilter::isNull() const
}
-bool NameFilter::cmpLessSameType(const BaseFilter& other) const
+bool NameFilter::cmpLessSameType(const HardFilter& other) const
{
assert(typeid(*this) == typeid(other)); //always given in this context!
@@ -357,15 +351,15 @@ Zstring NameFilter::uniqueClassIdentifier() const
void NameFilter::save(wxOutputStream& stream) const
{
- util::writeString(stream, includeFilterTmp);
- util::writeString(stream, excludeFilterTmp);
+ writeString(stream, includeFilterTmp);
+ writeString(stream, excludeFilterTmp);
}
-BaseFilter::FilterRef NameFilter::load(wxInputStream& stream) //"constructor"
+HardFilter::FilterRef NameFilter::load(wxInputStream& stream) //"constructor"
{
- const Zstring include = util::readString(stream);
- const Zstring exclude = util::readString(stream);
+ const Zstring include = readString<Zstring>(stream);
+ const Zstring exclude = readString<Zstring>(stream);
return FilterRef(new NameFilter(include, exclude));
}
diff --git a/library/filter.h b/library/hard_filter.h
index c1be61eb..4290e07a 100644
--- a/library/filter.h
+++ b/library/hard_filter.h
@@ -12,56 +12,60 @@
#include <boost/shared_ptr.hpp>
#include <wx/stream.h>
-namespace ffs3
+namespace zen
{
//------------------------------------------------------------------
-/* class hierarchy:
+/*
+Semantics of HardFilter:
+1. using it creates a NEW folder hierarchy! -> must be considered by <Automatic>-mode! (fortunately it turns out, doing nothing already has perfect semantics :)
+2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder!
- BaseFilter (interface)
+ class hierarchy:
+
+ HardFilter (interface)
/|\
_________|_____________
| | |
NullFilter NameFilter CombinedFilter
*/
-/*
-Semantics of BaseFilter:
-1. using it creates a NEW folder hierarchy! -> must be respected by <Automatic>-mode!
-2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder!
-*/
-
-class BaseFilter //interface for filtering
+class HardFilter //interface for filtering
{
public:
- virtual ~BaseFilter() {}
+ virtual ~HardFilter() {}
//filtering
virtual bool passFileFilter(const Zstring& relFilename) const = 0;
- virtual bool passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const = 0;
+ virtual bool passDirFilter (const Zstring& relDirname, bool* subObjMightMatch) const = 0;
//subObjMightMatch: file/dir in subdirectories could(!) match
//note: variable is only set if passDirFilter returns false!
virtual bool isNull() const = 0; //filter is equivalent to NullFilter, but may be technically slower
- //comparison
- bool operator<(const BaseFilter& other) const;
- bool operator==(const BaseFilter& other) const;
- bool operator!=(const BaseFilter& other) const;
-
- typedef boost::shared_ptr<const BaseFilter> FilterRef; //always bound by design!
+ typedef boost::shared_ptr<const HardFilter> FilterRef; //always bound by design!
//serialization
void saveFilter(wxOutputStream& stream) const; //serialize derived object
static FilterRef loadFilter(wxInputStream& stream); //CAVEAT!!! adapt this method for each new derivation!!!
private:
+ friend bool operator< (const HardFilter& lhs, const HardFilter& rhs);
+
virtual void save(wxOutputStream& stream) const = 0; //serialization
virtual Zstring uniqueClassIdentifier() const = 0; //get identifier, used for serialization
- virtual bool cmpLessSameType(const BaseFilter& other) const = 0; //typeid(*this) == typeid(other) in this context!
+ virtual bool cmpLessSameType(const HardFilter& other) const = 0; //typeid(*this) == typeid(other) in this context!
};
+inline bool operator==(const HardFilter& lhs, const HardFilter& rhs) { return !(lhs < rhs) && !(rhs < lhs); }
+inline bool operator!=(const HardFilter& lhs, const HardFilter& rhs) { return !(lhs == rhs); }
+
+
+//small helper method: merge two hard filters (thereby remove Null-filters)
+HardFilter::FilterRef combineFilters(const HardFilter::FilterRef& first,
+ const HardFilter::FilterRef& second);
-class NullFilter : public BaseFilter //no filtering at all
+
+class NullFilter : public HardFilter //no filtering at all
{
public:
virtual bool passFileFilter(const Zstring& relFilename) const;
@@ -69,15 +73,15 @@ public:
virtual bool isNull() const;
private:
- friend class BaseFilter;
+ friend class HardFilter;
virtual void save(wxOutputStream& stream) const {}
virtual Zstring uniqueClassIdentifier() const;
static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const BaseFilter& other) const;
+ virtual bool cmpLessSameType(const HardFilter& other) const;
};
-class NameFilter : public BaseFilter //standard filter by filename
+class NameFilter : public HardFilter //standard filter by filename
{
public:
NameFilter(const Zstring& includeFilter, const Zstring& excludeFilter);
@@ -87,11 +91,11 @@ public:
virtual bool isNull() const;
private:
- friend class BaseFilter;
+ friend class HardFilter;
virtual void save(wxOutputStream& stream) const;
virtual Zstring uniqueClassIdentifier() const;
static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const BaseFilter& other) const;
+ virtual bool cmpLessSameType(const HardFilter& other) const;
std::set<Zstring> filterFileIn; //upper case (windows)
std::set<Zstring> filterFolderIn; //
@@ -103,7 +107,7 @@ private:
};
-class CombinedFilter : public BaseFilter //combine two filters to match if and only if both match
+class CombinedFilter : public HardFilter //combine two filters to match if and only if both match
{
public:
CombinedFilter(const FilterRef& first, const FilterRef& second) : first_(first), second_(second) {}
@@ -113,22 +117,17 @@ public:
virtual bool isNull() const;
private:
- friend class BaseFilter;
+ friend class HardFilter;
virtual void save(wxOutputStream& stream) const;
virtual Zstring uniqueClassIdentifier() const;
static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const BaseFilter& other) const;
+ virtual bool cmpLessSameType(const HardFilter& other) const;
const FilterRef first_;
const FilterRef second_;
};
-//small helper method: remove Null-filters
-BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first,
- const BaseFilter::FilterRef& second);
-
-
@@ -147,7 +146,7 @@ BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first,
//---------------Inline Implementation---------------------------------------------------
inline
-BaseFilter::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor"
+HardFilter::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor"
{
return FilterRef(new NullFilter);
}
@@ -176,7 +175,7 @@ bool NullFilter::isNull() const
inline
-bool NullFilter::cmpLessSameType(const BaseFilter& other) const
+bool NullFilter::cmpLessSameType(const HardFilter& other) const
{
assert(typeid(*this) == typeid(other)); //always given in this context!
return false;
@@ -214,7 +213,7 @@ bool CombinedFilter::isNull() const
inline
-bool CombinedFilter::cmpLessSameType(const BaseFilter& other) const
+bool CombinedFilter::cmpLessSameType(const HardFilter& other) const
{
assert(typeid(*this) == typeid(other)); //always given in this context!
@@ -243,7 +242,7 @@ void CombinedFilter::save(wxOutputStream& stream) const
inline
-BaseFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor"
+HardFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor"
{
FilterRef first = loadFilter(stream);
FilterRef second = loadFilter(stream);
@@ -253,13 +252,13 @@ BaseFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor
inline
-BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first,
- const BaseFilter::FilterRef& second)
+HardFilter::FilterRef combineFilters(const HardFilter::FilterRef& first,
+ const HardFilter::FilterRef& second)
{
if (first->isNull())
{
if (second->isNull())
- return BaseFilter::FilterRef(new NullFilter);
+ return HardFilter::FilterRef(new NullFilter);
else
return second;
}
@@ -268,7 +267,7 @@ BaseFilter::FilterRef combineFilters(const BaseFilter::FilterRef& first,
if (second->isNull())
return first;
else
- return BaseFilter::FilterRef(new CombinedFilter(first, second));
+ return HardFilter::FilterRef(new CombinedFilter(first, second));
}
}
diff --git a/library/icon_buffer.cpp b/library/icon_buffer.cpp
index 14883deb..1b1706d2 100644
--- a/library/icon_buffer.cpp
+++ b/library/icon_buffer.cpp
@@ -7,10 +7,12 @@
#include "icon_buffer.h"
#include <wx/msgdlg.h>
#include <map>
+#include <vector>
#include <queue>
#include <set>
#include <wx/log.h>
#include "../shared/i18n.h"
+#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
#ifdef FFS_WIN
#include <wx/msw/wrapwin.h> //includes "windows.h"
@@ -22,11 +24,20 @@
#endif
-using ffs3::IconBuffer;
+using namespace zen;
+
+
+
+const size_t BUFFER_SIZE_MAX = 800; //maximum number of icons to buffer
+
+//---------------------------------------------------------------------------------------------------
+typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class
+//avoid reference-counted objects for shared data: NOT THREADSAFE!!! (implicitly shared variable: ref-count)
+//---------------------------------------------------------------------------------------------------
#ifdef FFS_WIN
-IconBuffer::BasicString IconBuffer::getFileExtension(const BasicString& filename)
+BasicString getFileExtension(const BasicString& filename)
{
const BasicString shortName = filename.AfterLast(Zchar('\\')); //warning: using windows file name separator!
@@ -37,7 +48,7 @@ IconBuffer::BasicString IconBuffer::getFileExtension(const BasicString& filename
//test for extension for icons that physically have to be retrieved from disc
-bool IconBuffer::isPriceyExtension(const IconBuffer::BasicString& extension)
+bool isPriceyExtension(const BasicString& extension)
{
static std::set<BasicString, LessFilename> exceptions; //not thread-safe, but called from worker thread only!
if (exceptions.empty())
@@ -57,7 +68,7 @@ bool IconBuffer::isPriceyExtension(const IconBuffer::BasicString& extension)
//################################################################################################################################################
-class IconBuffer::IconHolder //handle HICON/GdkPixbuf ownership WITHOUT ref-counting to allow thread-safe usage (in contrast to wxIcon)
+class IconHolder //handle HICON/GdkPixbuf ownership WITHOUT ref-counting to allow thread-safe usage (in contrast to wxIcon)
{
public:
#ifdef FFS_WIN
@@ -121,7 +132,88 @@ private:
};
-const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be sufficient...
+IconHolder getAssociatedIcon(const BasicString& filename)
+{
+#ifdef FFS_WIN
+ //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName"
+ //but no problem, directory formatting takes care that filenames are always absolute!
+
+ SHFILEINFO fileInfo = {}; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+ //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080
+
+ //NOTE: CoInitializeEx()/CoUninitialize() needs to be called for THIS thread!
+ ::SHGetFileInfo(filename.c_str(), //zen::removeLongPathPrefix(fileName), //::SHGetFileInfo() can't handle \\?\-prefix!
+ 0,
+ &fileInfo,
+ sizeof(fileInfo),
+ SHGFI_ICON | SHGFI_SMALLICON);
+
+ return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+
+#elif defined FFS_LINUX
+ //call Gtk::Main::init_gtkmm_internals() on application startup!!
+ try
+ {
+ Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails
+ Glib::RefPtr<Gio::FileInfo> fileInfo = fileObj->query_info(G_FILE_ATTRIBUTE_STANDARD_ICON);
+ if (fileInfo)
+ {
+ Glib::RefPtr<Gio::Icon> gicon = fileInfo->get_icon();
+ if (gicon)
+ {
+ Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
+ if (iconTheme)
+ {
+ Gtk::IconInfo iconInfo = iconTheme->lookup_icon(gicon, IconBuffer::ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN); //this may fail if icon is not installed on system
+ if (iconInfo)
+ {
+ Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconInfo.load_icon(); //render icon into Pixbuf
+ if (iconPixbuf)
+ return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
+ }
+ }
+ }
+ }
+ }
+ catch (const Glib::Error&) {}
+
+ try //fallback: icon lookup may fail because some icons are currently not present on system
+ {
+ Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
+ if (iconTheme)
+ {
+ Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", IconBuffer::ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ if (!iconPixbuf)
+ iconPixbuf = iconTheme->load_icon("text-x-generic", IconBuffer::ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ if (iconPixbuf)
+ return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
+ }
+ }
+ catch (const Glib::Error&) {}
+
+ //fallback fallback
+ return IconHolder();
+#endif
+}
+
+#ifdef FFS_WIN
+IconHolder getAssociatedIconByExt(const BasicString& extension)
+{
+ SHFILEINFO fileInfo = {}; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+
+ //no read-access to disk! determine icon by extension
+ ::SHGetFileInfo((Zstr("dummy.") + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name
+ FILE_ATTRIBUTE_NORMAL,
+ &fileInfo,
+ sizeof(fileInfo),
+ SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
+
+ return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+}
+#endif
+
+
+const wxIcon& getDirectoryIcon() //one folder icon should be sufficient...
{
static wxIcon folderIcon;
@@ -147,14 +239,14 @@ const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be suffici
}
#elif defined FFS_LINUX
- folderIcon = getAssociatedIcon(Zstr("/usr/")).toWxIcon(); //all directories will look like "/usr/"
+ folderIcon = ::getAssociatedIcon(Zstr("/usr/")).toWxIcon(); //all directories will look like "/usr/"
#endif
}
return folderIcon;
}
-const wxIcon& IconBuffer::getFileIcon() //in case one folder icon is sufficient...
+const wxIcon& getFileIcon() //in case one folder icon is sufficient...
{
static wxIcon fileIcon;
@@ -185,9 +277,9 @@ const wxIcon& IconBuffer::getFileIcon() //in case one folder icon is suffic
Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
if (iconTheme)
{
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", IconBuffer::ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
if (!iconPixbuf)
- iconPixbuf = iconTheme->load_icon("text-x-generic", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ iconPixbuf = iconTheme->load_icon("text-x-generic", IconBuffer::ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
if (iconPixbuf)
fileIcon.SetPixbuf(iconPixbuf->gobj_copy()); // transfer ownership!!
}
@@ -199,114 +291,89 @@ const wxIcon& IconBuffer::getFileIcon() //in case one folder icon is suffic
}
-IconBuffer::IconHolder IconBuffer::getAssociatedIcon(const BasicString& filename)
+//################################################################################################################################################
+class Buffer
{
-#ifdef FFS_WIN
- //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName"
- //but no problem, directory formatting takes care that filenames are always absolute!
+public:
+ //methods used by gui and worker thread
+ bool requestFileIcon(const Zstring& fileName, wxIcon* icon = NULL);
- SHFILEINFO fileInfo = {}; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
- //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080
+ //methods used by worker thread
+ void insertIntoBuffer(const BasicString& entryName, const IconHolder& icon);
- //NOTE: CoInitializeEx()/CoUninitialize() needs to be called for THIS thread!
- ::SHGetFileInfo(filename.c_str(), //ffs3::removeLongPathPrefix(fileName), //::SHGetFileInfo() can't handle \\?\-prefix!
- 0,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON);
+private:
+ //---------------------------------------------------------------------------------------------------
+ typedef std::map<BasicString, IconHolder, LessFilename> IconDB; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure!
+ typedef std::queue<BasicString> IconDbSequence; //entryName
+ //---------------------------------------------------------------------------------------------------
- return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+ //---------------------- Shared Data -------------------------
+ boost::mutex lockIconDB;
+ IconDB iconBuffer; //use synchronisation when accessing this!
+ IconDbSequence iconSequence; //save sequence of buffer entry to delete oldest elements
+ //------------------------------------------------------------
+};
-#elif defined FFS_LINUX
- //call Gtk::Main::init_gtkmm_internals() on application startup!!
- try
- {
- Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails
- Glib::RefPtr<Gio::FileInfo> fileInfo = fileObj->query_info(G_FILE_ATTRIBUTE_STANDARD_ICON);
- if (fileInfo)
- {
- Glib::RefPtr<Gio::Icon> gicon = fileInfo->get_icon();
- if (gicon)
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Gtk::IconInfo iconInfo = iconTheme->lookup_icon(gicon, ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN); //this may fail if icon is not installed on system
- if (iconInfo)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconInfo.load_icon(); //render icon into Pixbuf
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- }
- }
- }
- }
- catch (const Glib::Error&) {}
- try //fallback: icon lookup may fail because some icons are currently not present on system
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (!iconPixbuf)
- iconPixbuf = iconTheme->load_icon("text-x-generic", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- }
- catch (const Glib::Error&) {}
+bool Buffer::requestFileIcon(const Zstring& fileName, wxIcon* icon)
+{
+ boost::lock_guard<boost::mutex> dummy(lockIconDB);
- //fallback fallback
- return IconHolder();
+#ifdef FFS_WIN
+ //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
+ const BasicString extension = getFileExtension(fileName.c_str());
+ const BasicString searchString = isPriceyExtension(extension) ? fileName.c_str() : extension.c_str();
+ IconDB::const_iterator i = iconBuffer.find(searchString);
+#elif defined FFS_LINUX
+ IconDB::const_iterator i = iconBuffer.find(fileName.c_str());
#endif
-}
-#ifdef FFS_WIN
-IconBuffer::IconHolder IconBuffer::getAssociatedIconByExt(const BasicString& extension)
-{
- SHFILEINFO fileInfo = {}; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+ if (i == iconBuffer.end())
+ return false;
- //no read-access to disk! determine icon by extension
- ::SHGetFileInfo((Zstr("dummy.") + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name
- FILE_ATTRIBUTE_NORMAL,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
+ if (icon != NULL)
+ *icon = i->second.toWxIcon();
- return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+ return true;
}
-#endif
-namespace
-{
-//failure to initialize COM for each thread is a source of hard to reproduce bugs: https://sourceforge.net/tracker/?func=detail&aid=3160472&group_id=234430&atid=1093080
-struct ThreadInitializer
+void Buffer::insertIntoBuffer(const BasicString& entryName, const IconHolder& icon) //called by worker thread
{
- ThreadInitializer()
- {
-#ifdef FFS_WIN
- ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
-#endif
- }
+ boost::lock_guard<boost::mutex> dummy(lockIconDB);
+
+ //thread saftey: icon uses ref-counting! But is NOT shared with main thread!
+ const std::pair<IconDB::iterator, bool> rc = iconBuffer.insert(std::make_pair(entryName, icon));
+ if (rc.second) //if insertion took place
+ iconSequence.push(entryName); //note: sharing Zstring with IconDB!!!
+
+ assert(iconBuffer.size() == iconSequence.size());
- ~ThreadInitializer()
+ //remove elements if buffer becomes too big:
+ if (iconBuffer.size() > BUFFER_SIZE_MAX) //limit buffer size: critical because GDI resources are limited (e.g. 10000 on XP per process)
{
-#ifdef FFS_WIN
- ::CoUninitialize();
-#endif
+ //remove oldest element
+ iconBuffer.erase(iconSequence.front());
+ iconSequence.pop();
}
-};
}
-class IconBuffer::WorkerThread
+//################################################################################################################################################
+class WorkerThread
{
public:
- WorkerThread(IconBuffer& iconBuff);
- ~WorkerThread();
+ WorkerThread(Buffer& iconBuff) : iconBuffer(iconBuff)
+ {
+ threadObj = boost::thread(boost::ref(*this)); //localize all thread logic to this class!
+ }
+
+ ~WorkerThread()
+ {
+ setWorkload(std::vector<Zstring>()); //make sure interruption point is always reached!
+ threadObj.interrupt();
+ threadObj.join();
+ }
void setWorkload(const std::vector<Zstring>& load); //(re-)set new workload of icons to be retrieved
@@ -326,28 +393,13 @@ private:
} shared;
//------------------------------------------------------------
- IconBuffer& iconBuffer;
+ Buffer& iconBuffer;
boost::thread threadObj;
};
-IconBuffer::WorkerThread::WorkerThread(IconBuffer& iconBuff) :
- iconBuffer(iconBuff)
-{
- threadObj = boost::thread(boost::ref(*this)); //localize all thread logic to this class!
-}
-
-
-IconBuffer::WorkerThread::~WorkerThread()
-{
- setWorkload(std::vector<Zstring>()); //make sure interruption point is always reached!
- threadObj.interrupt();
- threadObj.join();
-}
-
-
-void IconBuffer::WorkerThread::setWorkload(const std::vector<Zstring>& load) //(re-)set new workload of icons to be retrieved
+void WorkerThread::setWorkload(const std::vector<Zstring>& load) //(re-)set new workload of icons to be retrieved
{
{
boost::lock_guard<boost::mutex> dummy(shared.mutex);
@@ -362,9 +414,16 @@ void IconBuffer::WorkerThread::setWorkload(const std::vector<Zstring>& load) //(
}
-void IconBuffer::WorkerThread::operator()() //thread entry
+void WorkerThread::operator()() //thread entry
{
- ThreadInitializer dummy1;
+ //failure to initialize COM for each thread is a source of hard to reproduce bugs: https://sourceforge.net/tracker/?func=detail&aid=3160472&group_id=234430&atid=1093080
+#ifdef FFS_WIN
+ struct ThreadInitializer
+ {
+ ThreadInitializer () { ::CoInitializeEx(NULL, COINIT_MULTITHREADED); }
+ ~ThreadInitializer() { ::CoUninitialize(); }
+ } dummy1;
+#endif
try
{
@@ -395,7 +454,7 @@ void IconBuffer::WorkerThread::operator()() //thread entry
}
-void IconBuffer::WorkerThread::doWork()
+void WorkerThread::doWork()
{
//do work: get the file icon.
while (true)
@@ -416,90 +475,47 @@ void IconBuffer::WorkerThread::doWork()
const BasicString extension = getFileExtension(fileName); //thread-safe: no sharing!
if (isPriceyExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
{
- const IconHolder newIcon = IconBuffer::getAssociatedIcon(fileName);
+ const IconHolder newIcon = getAssociatedIcon(fileName);
iconBuffer.insertIntoBuffer(fileName, newIcon);
}
else //no read-access to disk! determine icon by extension
{
- const IconHolder newIcon = IconBuffer::getAssociatedIconByExt(extension);
+ const IconHolder newIcon = getAssociatedIconByExt(extension);
iconBuffer.insertIntoBuffer(extension, newIcon);
}
#elif defined FFS_LINUX
- const IconHolder newIcon = IconBuffer::getAssociatedIcon(fileName);
+ const IconHolder newIcon = getAssociatedIcon(fileName);
iconBuffer.insertIntoBuffer(fileName, newIcon);
#endif
}
}
-//---------------------------------------------------------------------------------------------------
-class IconBuffer::IconDB : public std::map<BasicString, IconBuffer::IconHolder, LessFilename> {}; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure!
-class IconBuffer::IconDbSequence : public std::queue<BasicString> {}; //entryName
-//---------------------------------------------------------------------------------------------------
+//######################### redirect to impl #####################################################
-
-IconBuffer& IconBuffer::getInstance()
+struct IconBuffer::Pimpl
{
- static IconBuffer instance;
- return instance;
-}
+ Pimpl() : buffer(), worker(buffer) {} //might throw exceptions!
+ Buffer buffer;
+ WorkerThread worker;
+};
-IconBuffer::IconBuffer() :
- buffer( new IconDB),
- bufSequence(new IconDbSequence),
- worker( new WorkerThread(*this)) //might throw exceptions!
-{}
+IconBuffer::IconBuffer() : pimpl(new Pimpl) {}
IconBuffer::~IconBuffer() {} //auto_ptr<>: keep destructor non-inline
+const wxIcon& IconBuffer::getDirectoryIcon() { return ::getDirectoryIcon(); }
-bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon)
-{
- boost::lock_guard<boost::mutex> dummy(lockIconDB);
+const wxIcon& IconBuffer::getFileIcon() { return ::getFileIcon(); }
-#ifdef FFS_WIN
- //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- const BasicString extension = getFileExtension(fileName.c_str());
- const BasicString searchString = isPriceyExtension(extension) ? fileName.c_str() : extension.c_str();
- IconDB::const_iterator i = buffer->find(searchString);
-#elif defined FFS_LINUX
- IconDB::const_iterator i = buffer->find(fileName.c_str());
-#endif
-
- if (i == buffer->end())
- return false;
-
- if (icon != NULL)
- *icon = i->second.toWxIcon();
-
- return true;
-}
-
-
-void IconBuffer::setWorkload(const std::vector<Zstring>& load)
+IconBuffer& IconBuffer::getInstance()
{
- worker->setWorkload(load);
+ static IconBuffer instance;
+ return instance;
}
+bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon) { return pimpl->buffer.requestFileIcon(fileName, icon); }
-void IconBuffer::insertIntoBuffer(const BasicString& entryName, const IconHolder& icon) //called by worker thread
-{
- boost::lock_guard<boost::mutex> dummy(lockIconDB);
-
- //thread saftey: icon uses ref-counting! But is NOT shared with main thread!
- const std::pair<IconDB::iterator, bool> rc = buffer->insert(std::make_pair(entryName, icon));
- if (rc.second) //if insertion took place
- bufSequence->push(entryName); //note: sharing Zstring with IconDB!!!
-
- assert(buffer->size() == bufSequence->size());
-
- //remove elements if buffer becomes too big:
- if (buffer->size() > BUFFER_SIZE_MAX) //limit buffer size: critical because GDI resources are limited (e.g. 10000 on XP per process)
- {
- //remove oldest element
- buffer->erase(bufSequence->front());
- bufSequence->pop();
- }
-}
+void IconBuffer::setWorkload(const std::vector<Zstring>& load) { return pimpl->worker.setWorkload(load); }
diff --git a/library/icon_buffer.h b/library/icon_buffer.h
index b00a566d..5ab2740c 100644
--- a/library/icon_buffer.h
+++ b/library/icon_buffer.h
@@ -7,21 +7,18 @@
#ifndef ICONBUFFER_H_INCLUDED
#define ICONBUFFER_H_INCLUDED
-#include <vector>
#include "../shared/zstring.h"
#include <memory>
#include <wx/icon.h>
-#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
-namespace ffs3
+namespace zen
{
-
class IconBuffer
{
public:
- static const wxIcon& getDirectoryIcon(); //one folder icon should be sufficient...
- static const wxIcon& getFileIcon(); //in case one folder icon is sufficient...
+ static const wxIcon& getDirectoryIcon(); //one icon should be sufficient...
+ static const wxIcon& getFileIcon(); //
static IconBuffer& getInstance();
bool requestFileIcon(const Zstring& fileName, wxIcon* icon = NULL); //returns false if icon is not in buffer
@@ -37,36 +34,8 @@ private:
IconBuffer();
~IconBuffer();
- static const size_t BUFFER_SIZE_MAX = 800; //maximum number of icons to buffer
-
- class IconDB;
- class IconHolder;
- class IconDbSequence;
-
- //---------------------------------------------------------------------------------------------------
- typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class
- //avoid reference-counted objects for shared data: NOT THREADSAFE!!! (implicitly shared variable: ref-count)
- //---------------------------------------------------------------------------------------------------
-
- //methods used by worker thread
- void insertIntoBuffer(const BasicString& entryName, const IconHolder& icon);
-
- static IconHolder getAssociatedIcon(const BasicString& filename);
- static IconHolder getAssociatedIconByExt(const BasicString& extension);
-
-#ifdef FFS_WIN
- static BasicString getFileExtension(const BasicString& filename);
- static bool isPriceyExtension(const BasicString& extension);
-#endif
-
- //---------------------- Shared Data -------------------------
- boost::mutex lockIconDB;
- std::auto_ptr<IconDB> buffer; //use synchronisation when accessing this!
- std::auto_ptr<IconDbSequence> bufSequence; //save sequence of buffer entry to delete oldest elements
- //------------------------------------------------------------
-
- class WorkerThread;
- std::auto_ptr<WorkerThread> worker;
+ struct Pimpl;
+ std::auto_ptr<Pimpl> pimpl;
};
}
diff --git a/library/lock_holder.h b/library/lock_holder.h
new file mode 100644
index 00000000..b20646c3
--- /dev/null
+++ b/library/lock_holder.h
@@ -0,0 +1,52 @@
+#ifndef LOCK_HOLDER_H_INCLUDED
+#define LOCK_HOLDER_H_INCLUDED
+
+#include <map>
+#include "../shared/Zstring.h"
+#include "dir_lock.h"
+#include "status_handler.h"
+
+namespace zen
+{
+const Zstring LOCK_FILE_ENDING = Zstr("ffs_lock"); //intermediate locks created by DirLock use this extension, too!
+
+//convenience class for creating and holding locks for a number of directories
+class LockHolder
+{
+public:
+ void addDir(const Zstring& dirnameFmt, ProcessCallback& procCallback) //resolved dirname ending with path separator
+ {
+ if (dirnameFmt.empty()) return;
+ if (lockHolder.find(dirnameFmt) != lockHolder.end()) return;
+ assert(dirnameFmt.EndsWith(common::FILE_NAME_SEPARATOR)); //this is really the contract, formatting does other things as well, e.g. macro substitution
+
+ class WaitOnLockHandler : public DirLockCallback
+ {
+ public:
+ WaitOnLockHandler(ProcessCallback& pc) : pc_(pc) {}
+ virtual void requestUiRefresh() { pc_.requestUiRefresh(); } //allowed to throw exceptions
+ virtual void reportInfo(const Zstring& text) { pc_.reportInfo(text); }
+ private:
+ ProcessCallback& pc_;
+ } callback(procCallback);
+
+ try
+ {
+ lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync.") + LOCK_FILE_ENDING, &callback)));
+ }
+ catch (const FileError& e)
+ {
+ bool dummy = false; //this warning shall not be shown but logged only
+ procCallback.reportWarning(e.msg(), dummy);
+ }
+ }
+
+private:
+ typedef std::map<Zstring, DirLock, LessFilename> DirnameLockMap;
+ DirnameLockMap lockHolder;
+};
+
+}
+
+
+#endif // LOCK_HOLDER_H_INCLUDED
diff --git a/library/norm_filter.h b/library/norm_filter.h
new file mode 100644
index 00000000..2e55b43f
--- /dev/null
+++ b/library/norm_filter.h
@@ -0,0 +1,98 @@
+// **************************************************************************
+// * 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) *
+// **************************************************************************
+//
+#ifndef NORM_FILTER_H_INCLUDED
+#define NORM_FILTER_H_INCLUDED
+
+#include "hard_filter.h"
+#include "soft_filter.h"
+
+namespace zen
+{
+
+struct NormalizedFilter //grade-a filter: global/local filter settings combined, units resolved, ready for use
+{
+ NormalizedFilter(const HardFilter::FilterRef& hf, const SoftFilter& sf) : nameFilter(hf), timeSizeFilter(sf) {}
+
+ //"hard" filter: relevant during comparison, physically skips files
+ HardFilter::FilterRef nameFilter;
+ //"soft" filter: relevant after comparison; equivalent to user selection
+ SoftFilter timeSizeFilter;
+};
+namespace
+{
+//combine global and local filters via "logical and"
+NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig& local);
+
+inline
+bool isNullFilter(const FilterConfig& filterCfg)
+{
+ return NameFilter(filterCfg.includeFilter, filterCfg.excludeFilter).isNull() &&
+ SoftFilter(filterCfg.timeSpan, filterCfg.unitTimeSpan,
+ filterCfg.sizeMin, filterCfg.unitSizeMin,
+ filterCfg.sizeMax, filterCfg.unitSizeMax).isNull();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ----------------------- implementation -----------------------
+NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig& local)
+{
+ HardFilter::FilterRef globalName(new NameFilter(global.includeFilter, global.excludeFilter));
+ HardFilter::FilterRef localName (new NameFilter(local .includeFilter, local .excludeFilter));
+
+ SoftFilter globalTimeSize(global.timeSpan, global.unitTimeSpan,
+ global.sizeMin, global.unitSizeMin,
+ global.sizeMax, global.unitSizeMax);
+
+ SoftFilter localTimeSize(local.timeSpan, local.unitTimeSpan,
+ local.sizeMin, local.unitSizeMin,
+ local.sizeMax, local.unitSizeMax);
+
+ return NormalizedFilter(combineFilters(globalName, localName),
+ combineFilters(globalTimeSize, localTimeSize));
+}
+}
+}
+
+#endif //NORM_FILTER_H_INCLUDED
diff --git a/library/process_xml.cpp b/library/process_xml.cpp
index 9f95f5a3..0e591116 100644
--- a/library/process_xml.cpp
+++ b/library/process_xml.cpp
@@ -5,141 +5,96 @@
// **************************************************************************
//
#include "process_xml.h"
-#include "../shared/xml_base.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"
-using namespace ffs3;
+using namespace zen;
using namespace xmlAccess; //functionally needed!!!
-class FfsXmlParser : public xmlAccess::XmlParser
+XmlType xmlAccess::getXmlType(const wxString& filename) //throw()
{
-public:
- FfsXmlParser(const TiXmlElement* rootElement) : xmlAccess::XmlParser(rootElement) {}
-
- //read gui settings, all values retrieved are optional, so check for initial values! (== -1)
- void readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg);
- //read batch settings, all values retrieved are optional
- void readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg);
- //read global settings, valid for both GUI and batch mode, independent from configuration
- void readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg);
-
-private:
- //read alternate configuration (optional) => might point to NULL
- void readXmlLocalConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair);
-
- //read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully
- void readXmlMainConfig(MainConfiguration& mainCfg);
-};
-
-
-//write gui settings
-bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& outputCfg, TiXmlDocument& doc);
-//write batch settings
-bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& outputCfg, TiXmlDocument& doc);
-//write global settings
-bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& outputCfg, TiXmlDocument& doc);
-//write alternate configuration (optional) => might point to NULL
-void writeXmlLocalConfig(const FolderPairEnh& enhPair, TiXmlElement& parent);
-//write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully
-bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc);
-
-
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
-{
- //load XML
- if (!fileExists(wxToZ(filename)))
- throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
-
- TiXmlDocument doc;
- loadXmlDocument(filename, XML_GUI_CONFIG, doc); //throw (XmlError)
-
- FfsXmlParser parser(doc.RootElement());
- parser.readXmlGuiConfig(config); //read GUI layout configuration
-
- if (parser.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
- parser.getErrorMessageFormatted(), XmlError::WARNING);
-}
-
-
-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("\""));
-
- TiXmlDocument doc;
- loadXmlDocument(filename, XML_BATCH_CONFIG, doc); //throw (XmlError)
-
- FfsXmlParser parser(doc.RootElement());
- parser.readXmlBatchConfig(config); //read GUI layout configuration
+ try
+ {
+ TiXmlDocument doc;
+ loadXmlDocument(filename, doc); //throw (XmlError)
+ return getXmlType(doc);
+ }
+ catch (const XmlError&) {}
- if (parser.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
- parser.getErrorMessageFormatted(), XmlError::WARNING);
+ return XML_TYPE_OTHER;
}
-void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
+XmlType xmlAccess::getXmlType(const TiXmlDocument& doc) //throw()
{
- //load XML
- if (!fileExists(wxToZ(getGlobalConfigFile())))
- throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
-
- TiXmlDocument doc;
- loadXmlDocument(getGlobalConfigFile(), XML_GLOBAL_SETTINGS, doc); //throw (XmlError)
-
- FfsXmlParser parser(doc.RootElement());
- parser.readXmlGlobalSettings(config); //read GUI layout configuration
-
- if (parser.errorsOccurred())
- throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\"\n\n") +
- parser.getErrorMessageFormatted(), XmlError::WARNING);
+ const TiXmlElement* root = doc.RootElement();
+ if (root && root->ValueStr() == std::string("FreeFileSync"))
+ {
+ const char* cfgType = root->Attribute("XmlType");
+ if (cfgType)
+ {
+ const std::string type(cfgType);
+
+ if (type == "GUI")
+ return XML_TYPE_GUI;
+ else if (type == "BATCH")
+ return XML_TYPE_BATCH;
+ else if (type == "GLOBAL")
+ return XML_TYPE_GLOBAL;
+ }
+ }
+ return XML_TYPE_OTHER;
}
-void xmlAccess::writeConfig(const XmlGuiConfig& outputCfg, const wxString& filename)
+void xmlAccess::initXmlDocument(TiXmlDocument& doc, XmlType type) //throw()
{
- TiXmlDocument doc;
- getDefaultXmlDocument(XML_GUI_CONFIG, doc);
+ TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); //delete won't be necessary later; ownership passed to TiXmlDocument!
+ doc.LinkEndChild(decl);
- //populate and write XML tree
- if (!writeXmlGuiConfig(outputCfg, doc)) //add GUI layout configuration settings
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
+ TiXmlElement* root = new TiXmlElement("FreeFileSync");
+ doc.LinkEndChild(root);
- saveXmlDocument(filename, doc); //throw (XmlError)
+ switch (type)
+ {
+ case XML_TYPE_GUI:
+ addXmlAttribute("XmlType", "GUI", doc.RootElement());
+ break;
+ case XML_TYPE_BATCH:
+ addXmlAttribute("XmlType", "BATCH", doc.RootElement());
+ break;
+ case XML_TYPE_GLOBAL:
+ addXmlAttribute("XmlType", "GLOBAL", doc.RootElement());
+ break;
+ case XML_TYPE_OTHER:
+ break;
+ }
}
-void xmlAccess::writeConfig(const XmlBatchConfig& outputCfg, const wxString& filename)
+class FfsXmlErrorLogger : public xmlAccess::XmlErrorLogger
{
- TiXmlDocument doc;
- getDefaultXmlDocument(XML_BATCH_CONFIG, doc);
-
- //populate and write XML tree
- if (!writeXmlBatchConfig(outputCfg, doc)) //add batch configuration settings
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
-
- saveXmlDocument(filename, doc); //throw (XmlError)
-}
-
+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);
-void xmlAccess::writeConfig(const XmlGlobalSettings& outputCfg)
-{
- TiXmlDocument doc;
- getDefaultXmlDocument(XML_GLOBAL_SETTINGS, doc);
+private:
+ //read alternate configuration (optional) => might point to NULL
+ void readConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair);
+ void readFilter(const TiXmlElement& parent, FilterConfig& output);
- //populate and write XML tree
- if (!writeXmlGlobalSettings(outputCfg, doc)) //add GUI layout configuration settings
- throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+ //read basic FreefileSync settings (used by commandline and GUI)
+ void readConfig(const TiXmlElement* root, MainConfiguration& mainCfg);
+};
- saveXmlDocument(getGlobalConfigFile(), doc); //throw (XmlError)
-}
bool readXmlElement(const std::string& name, const TiXmlElement* parent, CompareVariant& output)
@@ -148,9 +103,9 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent, Compare
if (xmlAccess::readXmlElement(name, parent, dummy))
{
if (dummy == "ByTimeAndSize")
- output = ffs3::CMP_BY_TIME_SIZE;
+ output = zen::CMP_BY_TIME_SIZE;
else if (dummy == "ByContent")
- output = ffs3::CMP_BY_CONTENT;
+ output = zen::CMP_BY_CONTENT;
else
return false;
@@ -199,17 +154,35 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent, xmlAcce
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , ffs3::DeletionPolicy& output)
+bool readXmlElement(const std::string& name, const TiXmlElement* parent , OnGuiError& output)
+{
+ 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;
+}
+
+
+bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::DeletionPolicy& output)
{
std::string dummy;
if (xmlAccess::readXmlElement(name, parent, dummy))
{
if (dummy == "DeletePermanently")
- output = ffs3::DELETE_PERMANENTLY;
+ output = zen::DELETE_PERMANENTLY;
else if (dummy == "MoveToRecycleBin")
- output = ffs3::MOVE_TO_RECYCLE_BIN;
+ output = zen::MOVE_TO_RECYCLE_BIN;
else if (dummy == "MoveToCustomDirectory")
- output = ffs3::MOVE_TO_CUSTOM_DIRECTORY;
+ output = zen::MOVE_TO_CUSTOM_DIRECTORY;
else
return false;
@@ -219,17 +192,63 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent , ffs3::
}
-bool readXmlElement(const std::string& name, const TiXmlElement* parent , ffs3::SymLinkHandling& output)
+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 = ffs3::SYMLINK_IGNORE;
+ output = zen::SYMLINK_IGNORE;
else if (dummy == "UseDirectly")
- output = ffs3::SYMLINK_USE_DIRECTLY;
+ output = zen::SYMLINK_USE_DIRECTLY;
else if (dummy == "FollowLink")
- output = ffs3::SYMLINK_FOLLOW_LINK;
+ output = zen::SYMLINK_FOLLOW_LINK;
+ else
+ return false;
+
+ return true;
+ }
+ return false;
+}
+
+
+bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::UnitTime& output)
+{
+ 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 readXmlElement(const std::string& name, const TiXmlElement* parent , zen::UnitSize& output)
+{
+ std::string dummy;
+ if (xmlAccess::readXmlElement(name, parent, dummy))
+ {
+ 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;
@@ -239,6 +258,27 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent , ffs3::
}
+bool readXmlElement(const std::string& name, const TiXmlElement* parent , zen::SyncConfig::Variant& output)
+{
+ std::string dummy;
+ if (!xmlAccess::readXmlElement(name, parent, dummy))
+ return false;
+
+ 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;
+ else
+ return false;
+
+ return true;
+}
+
+
bool readXmlElement(const std::string& name, const TiXmlElement* parent, Zstring& output)
{
wxString dummy;
@@ -263,8 +303,27 @@ bool readXmlAttribute(const std::string& name, const TiXmlElement* node, xmlAcce
}
+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 FfsXmlParser::readXmlLocalConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair)
+void FfsXmlErrorLogger::readConfig(const TiXmlElement& folderPair, FolderPairEnh& enhPair)
{
//read folder pairs
readXmlElementLogging("Left", &folderPair, enhPair.leftDirectory);
@@ -273,46 +332,43 @@ void FfsXmlParser::readXmlLocalConfig(const TiXmlElement& folderPair, FolderPair
//###########################################################
//alternate sync configuration
- const TiXmlElement* altSyncConfig = TiXmlHandleConst(&folderPair).FirstChild("AlternateSyncConfig").ToElement();
- if (altSyncConfig)
+ const TiXmlElement* xmlAltSyncCfg = TiXmlHandleConst(&folderPair).FirstChild("AlternateSyncConfig").ToElement();
+ if (xmlAltSyncCfg)
{
AlternateSyncConfig* altSyncCfg = new AlternateSyncConfig;
enhPair.altSyncConfig.reset(altSyncCfg);
- const TiXmlElement* syncCfg = TiXmlHandleConst(altSyncConfig).FirstChild("Synchronization").ToElement();
- const TiXmlElement* syncDirections = TiXmlHandleConst(syncCfg).FirstChild("Directions").ToElement();
+ const TiXmlElement* xmlSyncDirections = TiXmlHandleConst(xmlAltSyncCfg).FirstChild("CustomDirections").ToElement();
//read sync configuration
- readXmlElementLogging("Automatic", syncCfg, altSyncCfg->syncConfiguration.automatic);
- readXmlElementLogging("LeftOnly", syncDirections, altSyncCfg->syncConfiguration.exLeftSideOnly);
- readXmlElementLogging("RightOnly", syncDirections, altSyncCfg->syncConfiguration.exRightSideOnly);
- readXmlElementLogging("LeftNewer", syncDirections, altSyncCfg->syncConfiguration.leftNewer);
- readXmlElementLogging("RightNewer", syncDirections, altSyncCfg->syncConfiguration.rightNewer);
- readXmlElementLogging("Different", syncDirections, altSyncCfg->syncConfiguration.different);
- readXmlElementLogging("Conflict", syncDirections, altSyncCfg->syncConfiguration.conflict);
-
- const TiXmlElement* miscSettings = TiXmlHandleConst(&folderPair).FirstChild("AlternateSyncConfig").FirstChild("Miscellaneous").ToElement();
- readXmlElementLogging("DeletionPolicy", miscSettings, altSyncCfg->handleDeletion);
- readXmlElementLogging("CustomDeletionFolder", miscSettings, altSyncCfg->customDeletionDirectory);
+ 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);
}
//###########################################################
//alternate filter configuration
const TiXmlElement* filterCfg = TiXmlHandleConst(&folderPair).FirstChild("LocalFilter").ToElement();
if (filterCfg)
- {
- //read filter settings
- readXmlElementLogging("Include", filterCfg, enhPair.localFilter.includeFilter);
- readXmlElementLogging("Exclude", filterCfg, enhPair.localFilter.excludeFilter);
- }
+ readFilter(*filterCfg, enhPair.localFilter);
}
-void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
+void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, MainConfiguration& mainCfg)
{
- TiXmlHandleConst hRoot(getRoot()); //custom const handle: TiXml API seems broken in this regard
+ 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
@@ -322,34 +378,31 @@ void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
readXmlElementLogging("HandleSymlinks", cmpSettings, mainCfg.handleSymlinks);
//###########################################################
- const TiXmlElement* syncCfg = hRoot.FirstChild("MainConfig").FirstChild("Synchronization").ToElement();
- const TiXmlElement* syncDirections = TiXmlHandleConst(syncCfg).FirstChild("Directions").ToElement();
+ const TiXmlElement* xmlSyncCfg = hRoot.FirstChild("MainConfig").FirstChild("SyncConfig").ToElement();
+ const TiXmlElement* syncDirections = TiXmlHandleConst(xmlSyncCfg).FirstChild("CustomDirections").ToElement();
//read sync configuration
- readXmlElementLogging("Automatic", syncCfg, mainCfg.syncConfiguration.automatic);
- readXmlElementLogging("LeftOnly", syncDirections, mainCfg.syncConfiguration.exLeftSideOnly);
- readXmlElementLogging("RightOnly", syncDirections, mainCfg.syncConfiguration.exRightSideOnly);
- readXmlElementLogging("LeftNewer", syncDirections, mainCfg.syncConfiguration.leftNewer);
- readXmlElementLogging("RightNewer", syncDirections, mainCfg.syncConfiguration.rightNewer);
- readXmlElementLogging("Different", syncDirections, mainCfg.syncConfiguration.different);
- readXmlElementLogging("Conflict", syncDirections, mainCfg.syncConfiguration.conflict);
+ readXmlElementLogging("Variant", xmlSyncCfg, mainCfg.syncConfiguration.var);
- //###########################################################
- const TiXmlElement* miscSettings = hRoot.FirstChild("MainConfig").FirstChild("Miscellaneous").ToElement();
+ 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", miscSettings, mainCfg.handleDeletion);
- readXmlElementLogging("CustomDeletionFolder", miscSettings, mainCfg.customDeletionDirectory);
+ readXmlElementLogging("DeletionPolicy", xmlSyncCfg, mainCfg.handleDeletion);
+ readXmlElementLogging("CustomDeletionFolder", xmlSyncCfg, mainCfg.customDeletionDirectory);
//###########################################################
- const TiXmlElement* filter = TiXmlHandleConst(miscSettings).FirstChild("Filter").ToElement();
+ const TiXmlElement* filter = TiXmlHandleConst(xmlMainConfig).FirstChild("GlobalFilter").ToElement();
//read filter settings
- Zstring includeFilter;
- Zstring excludeFilter;
- readXmlElementLogging("Include", filter, includeFilter);
- readXmlElementLogging("Exclude", filter, excludeFilter);
-
- mainCfg.globalFilter = FilterConfig(includeFilter, excludeFilter);
+ if (filter)
+ readFilter(*filter, mainCfg.globalFilter);
+ else
+ logError("GlobalFilter");
//###########################################################
const TiXmlElement* pairs = hRoot.FirstChild("MainConfig").FirstChild("FolderPairs").FirstChild("Pair").ToElement();
@@ -360,7 +413,7 @@ void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
while (pairs)
{
FolderPairEnh newPair;
- readXmlLocalConfig(*pairs, newPair);
+ readConfig(*pairs, newPair);
if (firstLoop) //read first folder pair
{
@@ -375,31 +428,27 @@ void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
}
-void FfsXmlParser::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg)
+void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlGuiConfig& outputCfg)
{
//read main config
- readXmlMainConfig(outputCfg.mainCfg);
+ readConfig(root, outputCfg.mainCfg);
//read GUI specific config data
- const TiXmlElement* guiConfig = TiXmlHandleConst(getRoot()).FirstChild("GuiConfig").ToElement();
-
- readXmlElementLogging("HideFiltered", guiConfig, outputCfg.hideFilteredElements);
-
- xmlAccess::OnError errorHand = ON_ERROR_POPUP;
- readXmlElementLogging("HandleError", guiConfig, errorHand);
- outputCfg.ignoreErrors = errorHand == xmlAccess::ON_ERROR_IGNORE;
+ const TiXmlElement* guiConfig = TiXmlHandleConst(root).FirstChild("GuiConfig").ToElement();
+ readXmlElementLogging("HideFiltered", guiConfig, outputCfg.hideFilteredElements);
+ readXmlElementLogging("HandleError", guiConfig, outputCfg.handleError);
readXmlElementLogging("SyncPreviewActive", guiConfig, outputCfg.syncPreviewEnabled);
}
-void FfsXmlParser::readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg)
+void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlBatchConfig& outputCfg)
{
//read main config
- readXmlMainConfig(outputCfg.mainCfg);
+ readConfig(root, outputCfg.mainCfg);
//read batch specific config
- const TiXmlElement* batchConfig = TiXmlHandleConst(getRoot()).FirstChild("BatchConfig").ToElement();
+ const TiXmlElement* batchConfig = TiXmlHandleConst(root).FirstChild("BatchConfig").ToElement();
readXmlElementLogging("Silent", batchConfig, outputCfg.silent);
readXmlElementLogging("LogfileDirectory", batchConfig, outputCfg.logFileDirectory);
@@ -408,10 +457,10 @@ void FfsXmlParser::readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg)
}
-void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg)
+void FfsXmlErrorLogger::readConfig(const TiXmlElement* root, xmlAccess::XmlGlobalSettings& outputCfg)
{
//read global settings
- const TiXmlElement* global = TiXmlHandleConst(getRoot()).FirstChild("Shared").ToElement();
+ const TiXmlElement* global = TiXmlHandleConst(root).FirstChild("Shared").ToElement();
//try to read program language setting
readXmlElementLogging("Language", global, outputCfg.programLanguage);
@@ -429,7 +478,7 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg
readXmlElementLogging("FileTimeTolerance", global, outputCfg.fileTimeTolerance);
- const TiXmlElement* optionalDialogs = TiXmlHandleConst(getRoot()).FirstChild("Shared").FirstChild("ShowOptionalDialogs").ToElement();
+ const TiXmlElement* optionalDialogs = TiXmlHandleConst(root).FirstChild("Shared").FirstChild("ShowOptionalDialogs").ToElement();
//folder dependency check
readXmlElementLogging("CheckForDependentFolders", optionalDialogs, outputCfg.optDialogs.warningDependentFolders);
@@ -452,7 +501,7 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg
//gui specific global settings (optional)
- const TiXmlElement* gui = TiXmlHandleConst(getRoot()).FirstChild("Gui").ToElement();
+ const TiXmlElement* gui = TiXmlHandleConst(root).FirstChild("Gui").ToElement();
const TiXmlElement* mainWindow = TiXmlHandleConst(gui).FirstChild("Windows").FirstChild("Main").ToElement();
//read application window size and position
@@ -508,19 +557,9 @@ void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg
rightColumn = rightColumn->NextSiblingElement();
}
- //load folder history elements
- const TiXmlElement* historyLeft = TiXmlHandleConst(mainWindow).FirstChild("FolderHistoryLeft").ToElement();
- //load max. history size
- readXmlAttributeLogging("MaximumSize", historyLeft, outputCfg.gui.folderHistLeftMax);
- //load config history elements
- readXmlElementLogging("Folder", historyLeft, outputCfg.gui.folderHistoryLeft);
-
-
- const TiXmlElement* historyRight = TiXmlHandleConst(mainWindow).FirstChild("FolderHistoryRight").ToElement();
- //load max. history size
- readXmlAttributeLogging("MaximumSize", historyRight, outputCfg.gui.folderHistRightMax);
- //load config history elements
- readXmlElementLogging("Folder", historyRight, outputCfg.gui.folderHistoryRight);
+ readXmlElementLogging("FolderHistoryLeft", mainWindow, outputCfg.gui.folderHistoryLeft);
+ readXmlElementLogging("FolderHistoryRight", mainWindow, outputCfg.gui.folderHistoryRight);
+ readXmlElementLogging("MaximumHistorySize", mainWindow, outputCfg.gui.folderHistMax);
readXmlElementLogging("Perspective", mainWindow, outputCfg.gui.guiPerspectiveLast);
@@ -562,10 +601,10 @@ void addXmlElement(const std::string& name, const CompareVariant variant, TiXmlE
{
switch (variant)
{
- case ffs3::CMP_BY_TIME_SIZE:
+ case zen::CMP_BY_TIME_SIZE:
xmlAccess::addXmlElement(name, std::string("ByTimeAndSize"), parent);
break;
- case ffs3::CMP_BY_CONTENT:
+ case zen::CMP_BY_CONTENT:
xmlAccess::addXmlElement(name, std::string("ByContent"), parent);
break;
}
@@ -606,40 +645,117 @@ void addXmlElement(const std::string& name, const xmlAccess::OnError value, TiXm
}
-void addXmlElement(const std::string& name, const ffs3::DeletionPolicy value, TiXmlElement* parent)
+void addXmlElement(const std::string& name, const OnGuiError value, TiXmlElement* parent)
{
switch (value)
{
- case ffs3::DELETE_PERMANENTLY:
+ case ON_GUIERROR_IGNORE:
+ xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
+ break;
+ case ON_GUIERROR_POPUP:
+ xmlAccess::addXmlElement(name, std::string("Popup"), parent);
+ break;
+ }
+}
+
+
+void addXmlElement(const std::string& name, const zen::DeletionPolicy value, TiXmlElement* parent)
+{
+ switch (value)
+ {
+ case zen::DELETE_PERMANENTLY:
xmlAccess::addXmlElement(name, std::string("DeletePermanently"), parent);
break;
- case ffs3::MOVE_TO_RECYCLE_BIN:
+ case zen::MOVE_TO_RECYCLE_BIN:
xmlAccess::addXmlElement(name, std::string("MoveToRecycleBin"), parent);
break;
- case ffs3::MOVE_TO_CUSTOM_DIRECTORY:
+ case zen::MOVE_TO_CUSTOM_DIRECTORY:
xmlAccess::addXmlElement(name, std::string("MoveToCustomDirectory"), parent);
break;
}
}
-void addXmlElement(const std::string& name, const ffs3::SymLinkHandling value, TiXmlElement* parent)
+void addXmlElement(const std::string& name, const zen::SymLinkHandling value, TiXmlElement* parent)
{
switch (value)
{
- case ffs3::SYMLINK_IGNORE:
+ case zen::SYMLINK_IGNORE:
xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
break;
- case ffs3::SYMLINK_USE_DIRECTLY:
+ case zen::SYMLINK_USE_DIRECTLY:
xmlAccess::addXmlElement(name, std::string("UseDirectly"), parent);
break;
- case ffs3::SYMLINK_FOLLOW_LINK:
+ case zen::SYMLINK_FOLLOW_LINK:
xmlAccess::addXmlElement(name, std::string("FollowLink"), parent);
break;
}
}
+void addXmlElement(const std::string& name, const zen::UnitTime value, TiXmlElement* parent)
+{
+ switch (value)
+ {
+ case zen::UTIME_NONE:
+ xmlAccess::addXmlElement(name, std::string("Inactive"), parent);
+ break;
+ case zen::UTIME_SEC:
+ xmlAccess::addXmlElement(name, std::string("Second"), parent);
+ break;
+ case zen::UTIME_MIN:
+ xmlAccess::addXmlElement(name, std::string("Minute"), parent);
+ break;
+ case zen::UTIME_HOUR:
+ xmlAccess::addXmlElement(name, std::string("Hour"), parent);
+ break;
+ case zen::UTIME_DAY:
+ xmlAccess::addXmlElement(name, std::string("Day"), parent);
+ break;
+ }
+}
+
+
+void addXmlElement(const std::string& name, zen::UnitSize value, TiXmlElement* parent)
+{
+ switch (value)
+ {
+ case zen::USIZE_NONE:
+ xmlAccess::addXmlElement(name, std::string("Inactive"), parent);
+ break;
+ case zen::USIZE_BYTE:
+ xmlAccess::addXmlElement(name, std::string("Byte"), parent);
+ break;
+ case zen::USIZE_KB:
+ xmlAccess::addXmlElement(name, std::string("KB"), parent);
+ break;
+ case zen::USIZE_MB:
+ xmlAccess::addXmlElement(name, std::string("MB"), parent);
+ break;
+ }
+}
+
+
+void addXmlElement(const std::string& name, SyncConfig::Variant value, TiXmlElement* parent)
+{
+ switch (value)
+ {
+ case SyncConfig::AUTOMATIC:
+ xmlAccess::addXmlElement(name, std::string("Automatic"), parent);
+ break;
+ case SyncConfig::MIRROR:
+ xmlAccess::addXmlElement(name, std::string("Mirror"), parent);
+ break;
+ case SyncConfig::UPDATE:
+ xmlAccess::addXmlElement(name, std::string("Update"), parent);
+ break;
+ case SyncConfig::CUSTOM:
+ xmlAccess::addXmlElement(name, std::string("Custom"), parent);
+ break;
+ }
+}
+
+
void addXmlElement(const std::string& name, const Zstring& value, TiXmlElement* parent)
{
xmlAccess::addXmlElement(name, wxString(zToWx(value)), parent);
@@ -652,6 +768,22 @@ void addXmlAttribute(const std::string& name, const xmlAccess::ColumnTypes value
}
+void writeFilter(const FilterConfig& input, TiXmlElement& parent)
+{
+ addXmlElement("Include", input.includeFilter, &parent);
+ addXmlElement("Exclude", input.excludeFilter, &parent);
+
+ addXmlElement("TimeSpan", input.timeSpan, &parent);
+ addXmlElement("UnitTimeSpan", input.unitTimeSpan, &parent);
+
+ addXmlElement("SizeMin", input.sizeMin, &parent);
+ addXmlElement("UnitSizeMin", input.unitSizeMin, &parent);
+
+ addXmlElement("SizeMax", input.sizeMax, &parent);
+ addXmlElement("UnitSizeMax", input.unitSizeMax, &parent);
+}
+
+
void writeXmlLocalConfig(const FolderPairEnh& enhPair, TiXmlElement& parent)
{
//write folder pairs
@@ -666,32 +798,25 @@ void writeXmlLocalConfig(const FolderPairEnh& enhPair, TiXmlElement& parent)
const AlternateSyncConfig* altSyncConfig = enhPair.altSyncConfig.get();
if (altSyncConfig)
{
- TiXmlElement* syncCfg = new TiXmlElement("AlternateSyncConfig");
- newfolderPair->LinkEndChild(syncCfg);
-
- TiXmlElement* syncSettings = new TiXmlElement("Synchronization");
- syncCfg->LinkEndChild(syncSettings);
+ TiXmlElement* xmlAltSyncCfg = new TiXmlElement("AlternateSyncConfig");
+ newfolderPair->LinkEndChild(xmlAltSyncCfg);
//write sync configuration
- addXmlElement("Automatic", altSyncConfig->syncConfiguration.automatic, syncSettings);
-
- TiXmlElement* syncDirections = new TiXmlElement("Directions");
- syncSettings->LinkEndChild(syncDirections);
+ addXmlElement("Variant", altSyncConfig->syncConfiguration.var, xmlAltSyncCfg);
- addXmlElement("LeftOnly", altSyncConfig->syncConfiguration.exLeftSideOnly, syncDirections);
- addXmlElement("RightOnly", altSyncConfig->syncConfiguration.exRightSideOnly, syncDirections);
- addXmlElement("LeftNewer", altSyncConfig->syncConfiguration.leftNewer, syncDirections);
- addXmlElement("RightNewer", altSyncConfig->syncConfiguration.rightNewer, syncDirections);
- addXmlElement("Different", altSyncConfig->syncConfiguration.different, syncDirections);
- addXmlElement("Conflict", altSyncConfig->syncConfiguration.conflict, syncDirections);
+ TiXmlElement* syncDirections = new TiXmlElement("CustomDirections");
+ xmlAltSyncCfg->LinkEndChild(syncDirections);
-
- TiXmlElement* miscSettings = new TiXmlElement("Miscellaneous");
- syncCfg->LinkEndChild(miscSettings);
+ 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);
//misc
- addXmlElement("DeletionPolicy", altSyncConfig->handleDeletion, miscSettings);
- addXmlElement("CustomDeletionFolder", altSyncConfig->customDeletionDirectory, miscSettings);
+ addXmlElement("DeletionPolicy", altSyncConfig->handleDeletion, xmlAltSyncCfg);
+ addXmlElement("CustomDeletionFolder", altSyncConfig->customDeletionDirectory, xmlAltSyncCfg);
}
//###########################################################
@@ -700,22 +825,18 @@ void writeXmlLocalConfig(const FolderPairEnh& enhPair, TiXmlElement& parent)
newfolderPair->LinkEndChild(filterCfg);
//write filter settings
- addXmlElement("Include", enhPair.localFilter.includeFilter, filterCfg);
- addXmlElement("Exclude", enhPair.localFilter.excludeFilter, filterCfg);
+ writeFilter(enhPair.localFilter, *filterCfg);
}
-bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc)
+void writeConfig(const MainConfiguration& mainCfg, TiXmlElement& root)
{
- TiXmlElement* root = doc.RootElement();
- if (!root) return false;
-
- TiXmlElement* settings = new TiXmlElement("MainConfig");
- root->LinkEndChild(settings);
+ TiXmlElement* xmlMainCfg = new TiXmlElement("MainConfig");
+ root.LinkEndChild(xmlMainCfg);
//###########################################################
TiXmlElement* cmpSettings = new TiXmlElement("Comparison");
- settings->LinkEndChild(cmpSettings);
+ xmlMainCfg->LinkEndChild(cmpSettings);
//write compare algorithm
addXmlElement("Variant", mainCfg.compareVar, cmpSettings);
@@ -724,40 +845,36 @@ bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc)
addXmlElement("HandleSymlinks", mainCfg.handleSymlinks, cmpSettings);
//###########################################################
- TiXmlElement* syncSettings = new TiXmlElement("Synchronization");
- settings->LinkEndChild(syncSettings);
+ TiXmlElement* xmlSyncCfg = new TiXmlElement("SyncConfig");
+ xmlMainCfg->LinkEndChild(xmlSyncCfg);
//write sync configuration
- addXmlElement("Automatic", mainCfg.syncConfiguration.automatic, syncSettings);
+ addXmlElement("Variant", mainCfg.syncConfiguration.var, xmlSyncCfg);
- TiXmlElement* syncDirections = new TiXmlElement("Directions");
- syncSettings->LinkEndChild(syncDirections);
+ TiXmlElement* syncDirections = new TiXmlElement("CustomDirections");
+ xmlSyncCfg->LinkEndChild(syncDirections);
- addXmlElement("LeftOnly", mainCfg.syncConfiguration.exLeftSideOnly, syncDirections);
- addXmlElement("RightOnly", mainCfg.syncConfiguration.exRightSideOnly, syncDirections);
- addXmlElement("LeftNewer", mainCfg.syncConfiguration.leftNewer, syncDirections);
- addXmlElement("RightNewer", mainCfg.syncConfiguration.rightNewer, syncDirections);
- addXmlElement("Different", mainCfg.syncConfiguration.different, syncDirections);
- addXmlElement("Conflict", mainCfg.syncConfiguration.conflict, 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);
//###########################################################
- TiXmlElement* miscSettings = new TiXmlElement("Miscellaneous");
- settings->LinkEndChild(miscSettings);
-
//write filter settings
- TiXmlElement* filter = new TiXmlElement("Filter");
- miscSettings->LinkEndChild(filter);
+ TiXmlElement* filter = new TiXmlElement("GlobalFilter");
+ xmlMainCfg->LinkEndChild(filter);
- addXmlElement("Include", mainCfg.globalFilter.includeFilter, filter);
- addXmlElement("Exclude", mainCfg.globalFilter.excludeFilter, filter);
+ writeFilter(mainCfg.globalFilter, *filter);
//other
- addXmlElement("DeletionPolicy", mainCfg.handleDeletion, miscSettings);
- addXmlElement("CustomDeletionFolder", mainCfg.customDeletionDirectory, miscSettings);
+ addXmlElement("DeletionPolicy", mainCfg.handleDeletion, xmlSyncCfg);
+ addXmlElement("CustomDeletionFolder", mainCfg.customDeletionDirectory, xmlSyncCfg);
//###########################################################
TiXmlElement* pairs = new TiXmlElement("FolderPairs");
- settings->LinkEndChild(pairs);
+ xmlMainCfg->LinkEndChild(pairs);
//write first folder pair
writeXmlLocalConfig(mainCfg.firstPair, *pairs);
@@ -765,65 +882,45 @@ bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc)
//write additional folder pairs
for (std::vector<FolderPairEnh>::const_iterator i = mainCfg.additionalPairs.begin(); i != mainCfg.additionalPairs.end(); ++i)
writeXmlLocalConfig(*i, *pairs);
-
- return true;
}
-bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg, TiXmlDocument& doc)
+void writeConfig(const xmlAccess::XmlGuiConfig& inputCfg, TiXmlElement& root)
{
//write main config
- if (!writeXmlMainConfig(inputCfg.mainCfg, doc))
- return false;
+ writeConfig(inputCfg.mainCfg, root);
//write GUI specific config
- TiXmlElement* root = doc.RootElement();
- if (!root) return false;
-
TiXmlElement* guiConfig = new TiXmlElement("GuiConfig");
- root->LinkEndChild(guiConfig);
+ root.LinkEndChild(guiConfig);
addXmlElement("HideFiltered", inputCfg.hideFilteredElements, guiConfig);
-
- addXmlElement("HandleError", inputCfg.ignoreErrors ? xmlAccess::ON_ERROR_IGNORE : xmlAccess::ON_ERROR_POPUP, guiConfig);
-
+ addXmlElement("HandleError", inputCfg.handleError, guiConfig);
addXmlElement("SyncPreviewActive", inputCfg.syncPreviewEnabled, guiConfig);
-
- return true;
}
-bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& inputCfg, TiXmlDocument& doc)
+void writeConfig(const xmlAccess::XmlBatchConfig& inputCfg, TiXmlElement& root)
{
//write main config
- if (!writeXmlMainConfig(inputCfg.mainCfg, doc))
- return false;
+ writeConfig(inputCfg.mainCfg, root);
//write GUI specific config
- TiXmlElement* root = doc.RootElement();
- if (!root) return false;
-
TiXmlElement* batchConfig = new TiXmlElement("BatchConfig");
- root->LinkEndChild(batchConfig);
+ root.LinkEndChild(batchConfig);
addXmlElement("Silent", inputCfg.silent, batchConfig);
addXmlElement("LogfileDirectory", inputCfg.logFileDirectory, batchConfig);
addXmlElement("LogfileCountMax", inputCfg.logFileCountMax, batchConfig);
addXmlElement("HandleError", inputCfg.handleError, batchConfig);
-
- return true;
}
-bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlDocument& doc)
+void writeConfig(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlElement& root)
{
- TiXmlElement* root = doc.RootElement();
- if (!root) return false;
-
- //###################################################################
//write global settings
TiXmlElement* global = new TiXmlElement("Shared");
- root->LinkEndChild(global);
+ root.LinkEndChild(global);
//program language
addXmlElement("Language", inputCfg.programLanguage, global);
@@ -870,7 +967,7 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD
//###################################################################
//write global gui settings
TiXmlElement* gui = new TiXmlElement("Gui");
- root->LinkEndChild(gui);
+ root.LinkEndChild(gui);
TiXmlElement* windows = new TiXmlElement("Windows");
gui->LinkEndChild(windows);
@@ -934,17 +1031,9 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD
addXmlAttribute("Width", colAttrib.width, subElement);
}
- //write folder history elements
- TiXmlElement* historyLeft = new TiXmlElement("FolderHistoryLeft");
- mainWindow->LinkEndChild(historyLeft);
- TiXmlElement* historyRight = new TiXmlElement("FolderHistoryRight");
- mainWindow->LinkEndChild(historyRight);
-
- addXmlAttribute("MaximumSize", inputCfg.gui.folderHistLeftMax, historyLeft);
- addXmlAttribute("MaximumSize", inputCfg.gui.folderHistRightMax, historyRight);
-
- addXmlElement("Folder", inputCfg.gui.folderHistoryLeft, historyLeft);
- addXmlElement("Folder", inputCfg.gui.folderHistoryRight, historyRight);
+ addXmlElement("FolderHistoryLeft", inputCfg.gui.folderHistoryLeft , mainWindow);
+ addXmlElement("FolderHistoryRight", inputCfg.gui.folderHistoryRight, mainWindow);
+ addXmlElement("MaximumHistorySize", inputCfg.gui.folderHistMax , mainWindow);
addXmlElement("Perspective", inputCfg.gui.guiPerspectiveLast, mainWindow);
@@ -975,15 +1064,13 @@ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlD
//write global batch settings
TiXmlElement* batch = new TiXmlElement("Batch");
- root->LinkEndChild(batch);
-
- return true;
+ root.LinkEndChild(batch);
}
wxString xmlAccess::getGlobalConfigFile()
{
- return ffs3::getConfigDir() + wxT("GlobalSettings.xml");
+ return zen::getConfigDir() + wxT("GlobalSettings.xml");
}
@@ -1013,10 +1100,15 @@ xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiCo
XmlBatchConfig output;
output.mainCfg = guiCfg.mainCfg;
- if (guiCfg.ignoreErrors)
- output.handleError = xmlAccess::ON_ERROR_IGNORE;
- else
- output.handleError = xmlAccess::ON_ERROR_POPUP;
+ 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;
+ }
return output;
}
@@ -1031,17 +1123,16 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filena
{
switch (xmlAccess::getXmlType(*i)) //throw()
{
- case XML_GUI_CONFIG:
+ case XML_TYPE_GUI:
guiCfgExists = true;
break;
- case XML_BATCH_CONFIG:
+ case XML_TYPE_BATCH:
batchCfgExists = true;
break;
- case XML_GLOBAL_SETTINGS:
- case XML_REAL_CONFIG:
- case XML_OTHER:
+ case XML_TYPE_GLOBAL:
+ case XML_TYPE_OTHER:
return MERGE_OTHER;
}
}
@@ -1087,24 +1178,23 @@ void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config
if (filenames.empty())
return;
- std::vector<ffs3::MainConfiguration> mainCfgs;
+ std::vector<zen::MainConfiguration> mainCfgs;
std::auto_ptr<XmlError> savedException;
for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
{
switch (getXmlType(*i))
{
- case XML_GUI_CONFIG:
+ case XML_TYPE_GUI:
mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(*i, savedException).mainCfg); //throw (xmlAccess::XmlError)
break;
- case XML_BATCH_CONFIG:
+ case XML_TYPE_BATCH:
mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(*i, savedException).mainCfg); //throw (xmlAccess::XmlError)
break;
- case XML_GLOBAL_SETTINGS:
- case XML_REAL_CONFIG:
- case XML_OTHER:
+ case XML_TYPE_GLOBAL:
+ case XML_TYPE_OTHER:
break;
}
}
@@ -1136,3 +1226,113 @@ void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlBatchCo
{
mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::XmlError)
}
+
+
+
+
+
+
+
+void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
+{
+ //load XML
+ if (!fileExists(wxToZ(filename)))
+ throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
+
+ TiXmlDocument doc;
+ loadXmlDocument(filename, doc); //throw (XmlError)
+
+ if (getXmlType(doc) != XML_TYPE_GUI) //throw()
+ throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
+
+ 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);
+}
+
+
+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("\""));
+
+ TiXmlDocument doc;
+ loadXmlDocument(filename, doc); //throw (XmlError)
+
+ if (getXmlType(doc) != XML_TYPE_BATCH) //throw()
+ throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
+
+ 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);
+}
+
+
+void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
+{
+ //load XML
+ if (!fileExists(wxToZ(getGlobalConfigFile())))
+ throw XmlError(wxString(_("File does not exist:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+
+ TiXmlDocument doc;
+ loadXmlDocument(getGlobalConfigFile(), doc); //throw (XmlError)
+
+ if (getXmlType(doc) != XML_TYPE_GLOBAL) //throw()
+ throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+
+ FfsXmlErrorLogger logger;
+ logger.readConfig(doc.RootElement(), config); //read GUI layout configuration
+
+ if (logger.errorsOccurred())
+ throw XmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\"\n\n") +
+ logger.getErrorMessageFormatted(), XmlError::WARNING);
+}
+
+
+void xmlAccess::writeConfig(const XmlGuiConfig& outputCfg, const wxString& filename)
+{
+ TiXmlDocument doc;
+ initXmlDocument(doc, XML_TYPE_GUI); //throw()
+
+ if (!doc.RootElement())
+ throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
+
+ writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
+
+ saveXmlDocument(filename, doc); //throw (XmlError)
+}
+
+
+void xmlAccess::writeConfig(const XmlBatchConfig& outputCfg, const wxString& filename)
+{
+ TiXmlDocument doc;
+ initXmlDocument(doc, XML_TYPE_BATCH); //throw()
+
+ if (!doc.RootElement())
+ throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + filename + wxT("\""));
+
+ writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
+
+ saveXmlDocument(filename, doc); //throw (XmlError)
+}
+
+
+void xmlAccess::writeConfig(const XmlGlobalSettings& outputCfg)
+{
+ TiXmlDocument doc;
+ initXmlDocument(doc, XML_TYPE_GLOBAL); //throw()
+
+ if (!doc.RootElement())
+ throw XmlError(wxString(_("Error writing file:")) + wxT("\n\"") + getGlobalConfigFile() + wxT("\""));
+
+ writeConfig(outputCfg, *doc.RootElement()); //add GUI layout configuration settings
+
+ saveXmlDocument(getGlobalConfigFile(), doc); //throw (XmlError)
+}
diff --git a/library/process_xml.h b/library/process_xml.h
index d627fc18..de566d15 100644
--- a/library/process_xml.h
+++ b/library/process_xml.h
@@ -7,13 +7,27 @@
#ifndef PROCESSXML_H_INCLUDED
#define PROCESSXML_H_INCLUDED
+#include "../shared/xml_base.h"
#include "../structures.h"
#include "../shared/xml_error.h"
-#include "../shared/i18n.h"
+#include "../shared/localization.h"
namespace xmlAccess
{
+enum XmlType
+{
+ XML_TYPE_GUI,
+ XML_TYPE_BATCH,
+ XML_TYPE_GLOBAL,
+ XML_TYPE_OTHER
+};
+
+XmlType getXmlType(const TiXmlDocument& doc); //throw()
+XmlType getXmlType(const wxString& filename); //throw()
+void initXmlDocument(TiXmlDocument& doc, XmlType type); //throw()
+
+
enum OnError
{
ON_ERROR_POPUP,
@@ -21,6 +35,12 @@ enum OnError
ON_ERROR_EXIT
};
+enum OnGuiError
+{
+ ON_GUIERROR_POPUP,
+ ON_GUIERROR_IGNORE
+};
+
enum ColumnTypes
{
DIRECTORY, //this needs to begin with 0 and be continuous (some code relies on it)
@@ -52,20 +72,21 @@ struct XmlGuiConfig
{
XmlGuiConfig() :
hideFilteredElements(false),
- ignoreErrors(false),
+ handleError(ON_GUIERROR_POPUP),
syncPreviewEnabled(true) {} //initialize values
- ffs3::MainConfiguration mainCfg;
+ zen::MainConfiguration mainCfg;
bool hideFilteredElements;
- bool ignoreErrors; //reaction on error situation during synchronization
+
+ OnGuiError handleError; //reaction on error situation during synchronization
bool syncPreviewEnabled;
bool operator==(const XmlGuiConfig& other) const
{
return mainCfg == other.mainCfg &&
hideFilteredElements == other.hideFilteredElements &&
- ignoreErrors == other.ignoreErrors &&
+ handleError == other.handleError &&
syncPreviewEnabled == other.syncPreviewEnabled;
}
@@ -83,7 +104,7 @@ struct XmlBatchConfig
logFileCountMax(200),
handleError(ON_ERROR_POPUP) {}
- ffs3::MainConfiguration mainCfg;
+ zen::MainConfiguration mainCfg;
bool silent;
wxString logFileDirectory;
@@ -119,7 +140,7 @@ struct XmlGlobalSettings
//---------------------------------------------------------------------
//Shared (GUI/BATCH) settings
XmlGlobalSettings() :
- programLanguage(ffs3::retrieveSystemLanguage()),
+ programLanguage(zen::retrieveSystemLanguage()),
copyLockedFiles(true),
copyFilePermissions(false),
fileTimeTolerance(2), //default 2s: FAT vs NTFS
@@ -145,8 +166,7 @@ struct XmlGlobalSettings
isMaximized(false),
autoAdjustColumnsLeft(false),
autoAdjustColumnsRight(false),
- folderHistLeftMax(12),
- folderHistRightMax(12),
+ folderHistMax(12),
deleteOnBothSides(false),
useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message
#ifdef FFS_WIN
@@ -164,7 +184,7 @@ struct XmlGlobalSettings
externelApplications.push_back(std::make_pair(wxT("Show in Explorer"), //mark for extraction: _("Show in Explorer")
wxT("explorer /select, \"%name\"")));
externelApplications.push_back(std::make_pair(wxT("Open with default application"), //mark for extraction: _("Open with default application")
- wxT("cmd /c start \"\" \"%name\"")));
+ wxT("\"%name\"")));
#elif defined FFS_LINUX
externelApplications.push_back(std::make_pair(wxT("Browse directory"), //mark for extraction: _("Browse directory")
wxT("xdg-open \"%dir\"")));
@@ -191,10 +211,8 @@ struct XmlGlobalSettings
wxString lastUsedConfigFile;
std::vector<wxString> folderHistoryLeft;
- unsigned int folderHistLeftMax;
-
std::vector<wxString> folderHistoryRight;
- unsigned int folderHistRightMax;
+ unsigned int folderHistMax;
bool deleteOnBothSides;
bool useRecyclerForManualDeletion;
diff --git a/library/resources.cpp b/library/resources.cpp
index d07e66a8..abdfdf51 100644
--- a/library/resources.cpp
+++ b/library/resources.cpp
@@ -15,7 +15,7 @@
#include <memory>
#include "../shared/standard_paths.h"
-using namespace ffs3;
+using namespace zen;
const GlobalResources& GlobalResources::instance()
@@ -69,7 +69,7 @@ void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation* animation)
void GlobalResources::load()
{
- wxFFileInputStream input(ffs3::getResourceDir() + wxT("Resources.dat"));
+ wxFFileInputStream input(zen::getResourceDir() + wxT("Resources.dat"));
if (input.IsOk()) //if not... we don't want to react too harsh here
{
//activate support for .png files
diff --git a/library/soft_filter.cpp b/library/soft_filter.cpp
deleted file mode 100644
index 1c191b98..00000000
--- a/library/soft_filter.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// **************************************************************************
-// * 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 "soft_filter.h"
-
-
-
diff --git a/library/soft_filter.h b/library/soft_filter.h
index 4e6732a3..82ba0ba2 100644
--- a/library/soft_filter.h
+++ b/library/soft_filter.h
@@ -4,47 +4,53 @@
// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
// **************************************************************************
//
-#ifndef SOFTFILTER_H_INCLUDED
-#define SOFTFILTER_H_INCLUDED
+#ifndef SOFT_FILTER_H_INCLUDED
+#define SOFT_FILTER_H_INCLUDED
-#include "../file_hierarchy.h"
-#include <wx/timer.h>
+#include <algorithm>
+#include <limits>
+#include "../structures.h"
+#include <wx/stopwatch.h>
+
+namespace zen
+{
/*
Semantics of SoftFilter:
1. It potentially may match only one side => it MUST NOT be applied while traversing a single folder to avoid mismatches
2. => it is applied after traversing and just marks rows, (NO deletions after comparison are allowed)
-3. => not relevant for <Automatic>-mode! ;)
-
--> SoftFilter is equivalent to a user temporarily (de-)selecting rows
+3. => equivalent to a user temporarily (de-)selecting rows -> not relevant for <Automatic>-mode! ;)
*/
-namespace ffs3
-{
-
class SoftFilter
{
public:
- SoftFilter(size_t timeWindow) :
- timeWindow_(timeWindow),
- currentTime(wxGetUTCTime()) {}
+ SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
+ size_t sizeMin, UnitSize unitSizeMin,
+ size_t sizeMax, UnitSize unitSizeMax);
- // typedef boost::shared_ptr<const SoftFilter> FilterRef; //always bound by design!
+ bool matchTime(zen::Int64 writeTime) const { return currentTime - writeTime <= timeSpan_; }
+ bool matchSize(zen::UInt64 fileSize) const { return sizeMin_ <= fileSize && fileSize <= sizeMax_; }
+ bool isNull() const; //filter is equivalent to NullFilter, but may be technically slower
- bool passFilter(const FileMapping& fileMap) const;
- bool passFilter(const DirMapping& dirMap) const;
+ //small helper method: merge two soft filters
+ friend SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second);
private:
- const size_t timeWindow_; //point in time from "now" (in seconds) for oldest modification date to be allowed
- const long currentTime; //number of seconds since GMT 00:00:00 Jan 1st 1970.
+ SoftFilter(zen::Int64 timeSpan,
+ zen::UInt64 sizeMin,
+ zen::UInt64 sizeMax);
+
+ zen::Int64 timeSpan_; //unit: seconds
+ zen::UInt64 sizeMin_; //unit: bytes
+ zen::UInt64 sizeMax_; //unit: bytes
+ zen::Int64 currentTime;
};
+}
+
+
+
-//SoftFilter::FilterRef combineFilters(const SoftFilter& first,
-// const SoftFilter& second);
-//
-//
-//
-//
@@ -62,22 +68,54 @@ private:
-//---------------Inline Implementation---------------------------------------------------
+
+
+
+
+
+
+
+// ----------------------- implementation -----------------------
+namespace zen
+{
inline
-bool SoftFilter::passFilter(const FileMapping& fileMap) const
+SoftFilter::SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
+ size_t sizeMin, UnitSize unitSizeMin,
+ size_t sizeMax, UnitSize unitSizeMax) :
+ currentTime(wxGetUTCTime())
{
- return (!fileMap.isEmpty<LEFT_SIDE>() &&
- currentTime <= fileMap.getLastWriteTime<LEFT_SIDE>() + timeWindow_) ||
- (!fileMap.isEmpty<RIGHT_SIDE>() &&
- currentTime <= fileMap.getLastWriteTime<RIGHT_SIDE>() + timeWindow_);
+ zen::resolveUnits(timeSpan, unitTimeSpan,
+ sizeMin, unitSizeMin,
+ sizeMax, unitSizeMax,
+ timeSpan_, //unit: seconds
+ sizeMin_, //unit: bytes
+ sizeMax_); //unit: bytes
}
+inline
+SoftFilter::SoftFilter(zen::Int64 timeSpan,
+ zen::UInt64 sizeMin,
+ zen::UInt64 sizeMax) :
+ timeSpan_(timeSpan),
+ sizeMin_ (sizeMin),
+ sizeMax_ (sizeMax),
+ currentTime(wxGetUTCTime()) {}
+
+inline
+SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second)
+{
+ return SoftFilter(std::min(first.timeSpan_, second.timeSpan_),
+ std::max(first.sizeMin_, second.sizeMin_),
+ std::min(first.sizeMax_, second.sizeMax_));
+}
inline
-bool SoftFilter::passFilter(const DirMapping& dirMap) const
+bool SoftFilter::isNull() const //filter is equivalent to NullFilter, but may be technically slower
{
- return false;
+ return timeSpan_ == std::numeric_limits<zen::Int64>::max() &&
+ sizeMin_ == 0U &&
+ sizeMax_ == std::numeric_limits<zen::UInt64>::max();
}
}
-#endif // SOFTFILTER_H_INCLUDED
+#endif // SOFT_FILTER_H_INCLUDED
diff --git a/library/statistics.cpp b/library/statistics.cpp
index d5cce670..c2ba8c0c 100644
--- a/library/statistics.cpp
+++ b/library/statistics.cpp
@@ -16,6 +16,8 @@
#include "../shared/assert_static.h"
+using namespace zen;
+
RetrieveStatistics::RetrieveStatistics() :
timer(new wxStopWatch) {}
@@ -31,12 +33,11 @@ RetrieveStatistics::~RetrieveStatistics()
for (std::vector<StatEntry>::const_iterator i = data.begin(); i != data.end(); ++i)
{
- using common::numberToString;
- outputFile.Write(numberToString(i->time));
+ outputFile.Write(toString<wxString>(i->time));
outputFile.Write(wxT(";"));
- outputFile.Write(numberToString(i->objects));
+ outputFile.Write(toString<wxString>(i->objects));
outputFile.Write(wxT(";"));
- outputFile.Write(numberToString(i->value));
+ outputFile.Write(toString<wxString>(i->value));
outputFile.Write(wxT("\n"));
}
}
@@ -64,26 +65,34 @@ bool isNull(T number)
}
+enum UnitRemTime
+{
+ URT_SEC,
+ URT_MIN,
+ URT_HOUR,
+ URT_DAY
+};
+
+
inline
wxString Statistics::formatRemainingTime(double timeInMs) const
{
- bool unitSec = true;
double remainingTime = timeInMs / 1000;
- wxString output = _("%x sec");
+ //determine preferred unit
+ UnitRemTime unit = URT_SEC;
if (remainingTime > 55)
{
- unitSec = false;
+ unit = URT_MIN;
remainingTime /= 60;
- output = _("%x min");
if (remainingTime > 59)
{
+ unit = URT_HOUR;
remainingTime /= 60;
- output = _("%x hour(s)");
if (remainingTime > 23)
{
+ unit = URT_DAY;
remainingTime /= 24;
- output = _("%x day(s)");
}
}
}
@@ -91,14 +100,14 @@ wxString Statistics::formatRemainingTime(double timeInMs) const
int formattedTime = common::round(remainingTime);
//reduce precision to 5 seconds
- if (unitSec && formattedTime % 5 != 0)
+ if (unit == URT_SEC && formattedTime % 5 != 0)
formattedTime += 5 - formattedTime % 5; //"ceiling"
//avoid "jumping back and forth" when fluctuating around .5
if (remainingTimeLast < formattedTime)
{
- if (unitSec)
+ if (unit == URT_SEC)
{
formattedTime = common::round(remainingTime);
formattedTime -= formattedTime % 5; //"floor"
@@ -108,8 +117,24 @@ wxString Statistics::formatRemainingTime(double timeInMs) const
}
remainingTimeLast = formattedTime;
- output.Replace(wxT("%x"), common::numberToString(formattedTime));
-
+ //generate output message
+ wxString output;
+ switch (unit)
+ {
+ case URT_SEC:
+ output = _P("1 sec", "%x sec", formattedTime);
+ break;
+ case URT_MIN:
+ output = _P("1 min", "%x min", formattedTime);
+ break;
+ case URT_HOUR:
+ output = _P("1 hour", "%x hours", formattedTime);
+ break;
+ case URT_DAY:
+ output = _P("1 day", "%x days", formattedTime);
+ break;
+ }
+ output.Replace(wxT("%x"), zen::toStringSep(formattedTime));
return output;
//+ wxT("(") + common::numberToWxString(common::round(timeInMs / 1000)) + wxT(")");
}
@@ -144,10 +169,10 @@ void Statistics::addMeasurement(int objectsCurrent, double dataCurrent)
//insert new record
if (!measurements.empty())
- {
- //assert(dataCurrent >= (--measurements.end())->second.data);
- measurements.insert(--measurements.end(), newEntry); //use fact that time is monotonously ascending
- }
+ {
+ //assert(dataCurrent >= (--measurements.end())->second.data);
+ measurements.insert(--measurements.end(), newEntry); //use fact that time is monotonously ascending
+ }
else
measurements.insert(newEntry);
@@ -202,7 +227,7 @@ wxString Statistics::getBytesPerSecond() const
const double dataDelta = backRecord.second.data - frontRecord.second.data;
if (!isNull(timeDelta))
- return ffs3::formatFilesizeToShortString(dataDelta * 1000 / timeDelta) + _("/sec");
+ return zen::formatFilesizeToShortString(zen::UInt64(dataDelta * 1000 / timeDelta)) + _("/sec");
}
return wxT("-"); //fallback
@@ -273,7 +298,7 @@ wxString Statistics::getRemainingTime(const int objectsCurrent, const double dat
const double X = dataCurrent - dataLast;
dataLast = dataCurrent;
- const wxLongLong timeCurrent = wxGetLocalTimeMillis();
+ const zen::Int64 timeCurrent = wxGetLocalTimeMillis();
const double F = (timeCurrent - timeLast).ToDouble();
timeLast = timeCurrent;
@@ -298,7 +323,7 @@ wxString Statistics::getRemainingTime(const int objectsCurrent, const double dat
const double X = dataCurrent - dataLast; //do not set dataLast, timeLast variables here, but write dummy record instead
if (!isNull(X))
{
- const wxLongLong timeCurrent = wxGetLocalTimeMillis();
+ const zen::Int64 timeCurrent = wxGetLocalTimeMillis();
const double F = (timeCurrent - timeLast).ToDouble();
record modifyEntry;
diff --git a/library/status_handler.cpp b/library/status_handler.cpp
index e81746a4..0a131899 100644
--- a/library/status_handler.cpp
+++ b/library/status_handler.cpp
@@ -21,8 +21,8 @@ void updateUiNow()
bool updateUiIsAllowed()
{
- static wxLongLong lastExec = 0;
- const wxLongLong newExec = wxGetLocalTimeMillis();
+ static wxMilliClock_t lastExec = 0;
+ const wxMilliClock_t newExec = wxGetLocalTimeMillis();
if (newExec - lastExec >= UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary
{
diff --git a/library/status_handler.h b/library/status_handler.h
index 2dde4fd9..c3a016d5 100644
--- a/library/status_handler.h
+++ b/library/status_handler.h
@@ -7,9 +7,9 @@
#ifndef STATUSHANDLER_H_INCLUDED
#define STATUSHANDLER_H_INCLUDED
-#include <wx/longlong.h>
+#include <wx/string.h>
#include "../shared/zstring.h"
-
+#include "../shared/int64.h"
const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
@@ -35,11 +35,10 @@ public:
};
-class StatusHandler
+//report status during comparison and synchronization
+struct ProcessCallback
{
-public:
- StatusHandler() : abortRequested(false) {}
- virtual ~StatusHandler() {}
+ virtual ~ProcessCallback() {}
//identifiers of different phases
enum Process
@@ -51,54 +50,56 @@ public:
};
//these methods have to be implemented in the derived classes to handle error and status information
- virtual void initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
- virtual void updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) = 0; //called periodically after data was processed
+ virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
+ virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //called periodically after data was processed
virtual void reportInfo(const Zstring& text) = 0;
//this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
virtual void forceUiRefresh() = 0;
- void requestUiRefresh(bool allowAbort = true); //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
- void requestAbortion(); //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished)
- bool abortIsRequested();
+ virtual void requestUiRefresh(bool allowExceptions = true) = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
+
+ virtual bool abortIsRequested() = 0; //thanks to Windows C-Api not supporting exceptions we need this one...
//error handling:
virtual ErrorHandler::Response reportError(const wxString& errorMessage) = 0; //recoverable error situation
virtual void reportFatalError(const wxString& errorMessage) = 0; //non-recoverable error situation, implement abort!
- virtual void reportWarning(const wxString& warningMessage, bool& warningActive) = 0;
+ virtual void reportWarning (const wxString& warningMessage, bool& warningActive) = 0;
+};
-private:
- virtual void abortThisProcess() = 0;
- bool abortRequested;
+//gui may want to abort process
+struct AbortCallback
+{
+ virtual ~AbortCallback() {}
+ virtual void requestAbortion() = 0;
};
-
-//##############################################################################
-inline
-void StatusHandler::requestUiRefresh(bool allowAbort)
+//actual callback implementation will have to satisfy "process" and "gui"
+class StatusHandler : public ProcessCallback, public AbortCallback
{
- if (updateUiIsAllowed()) //test if specific time span between ui updates is over
- forceUiRefresh();
+public:
+ StatusHandler() : abortRequested(false) {}
- if (abortRequested && allowAbort)
- abortThisProcess(); //abort can be triggered by requestAbortion()
-}
+ virtual void requestUiRefresh(bool allowExceptions)
+ {
+ if (updateUiIsAllowed()) //test if specific time span between ui updates is over
+ forceUiRefresh();
+ if (abortRequested && allowExceptions)
+ abortThisProcess(); //abort can be triggered by requestAbortion()
+ }
-inline
-void StatusHandler::requestAbortion()
-{
- abortRequested = true;
-}
+ virtual void requestAbortion() { abortRequested = true; } //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished)
+ virtual bool abortIsRequested() { return abortRequested; }
+ virtual void abortThisProcess() = 0;
+
+private:
+ bool abortRequested;
+};
-inline
-bool StatusHandler::abortIsRequested()
-{
- return abortRequested;
-}
#endif // STATUSHANDLER_H_INCLUDED
bgstack15