summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/custom_grid.cpp42
-rw-r--r--library/db_file.cpp386
-rw-r--r--library/db_file.h2
-rw-r--r--library/dir_lock.cpp69
-rw-r--r--library/dir_lock.h3
-rw-r--r--library/error_log.cpp13
-rw-r--r--library/error_log.h3
-rw-r--r--library/hard_filter.cpp47
-rw-r--r--library/icon_buffer.cpp192
-rw-r--r--library/icon_buffer.h4
-rw-r--r--library/lock_holder.h8
-rw-r--r--library/process_xml.cpp21
-rw-r--r--library/process_xml.h6
-rw-r--r--library/resources.cpp4
-rw-r--r--library/soft_filter.h45
-rw-r--r--library/statistics.cpp4
-rw-r--r--library/status_handler.h51
17 files changed, 463 insertions, 437 deletions
diff --git a/library/custom_grid.cpp b/library/custom_grid.cpp
index c2b87b5d..97b608fb 100644
--- a/library/custom_grid.cpp
+++ b/library/custom_grid.cpp
@@ -5,7 +5,6 @@
// **************************************************************************
//
#include "custom_grid.h"
-#include "../shared/system_constants.h"
#include "resources.h"
#include <wx/dc.h>
#include "../shared/util.h"
@@ -283,16 +282,16 @@ protected:
switch (colType_)
{
case xmlAccess::FULL_PATH:
- value = zToWx(fileObj.getFullName<side>().BeforeLast(common::FILE_NAME_SEPARATOR));
+ value = toWx(fileObj.getFullName<side>().BeforeLast(FILE_NAME_SEPARATOR));
break;
case xmlAccess::FILENAME: //filename
- value = zToWx(fileObj.getShortName<side>());
+ value = toWx(fileObj.getShortName<side>());
break;
case xmlAccess::REL_PATH: //relative path
- value = zToWx(fileObj.getParentRelativeName());
+ value = toWx(fileObj.getParentRelativeName());
break;
case xmlAccess::DIRECTORY:
- value = zToWx(fileObj.getBaseDirPf<side>());
+ value = toWx(fileObj.getBaseDirPf<side>());
break;
case xmlAccess::SIZE: //file size
value = zen::toStringSep(fileObj.getFileSize<side>());
@@ -301,7 +300,7 @@ protected:
value = zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
break;
case xmlAccess::EXTENSION: //file extension
- value = zToWx(fileObj.getExtension<side>());
+ value = toWx(fileObj.getExtension<side>());
break;
}
}
@@ -311,16 +310,16 @@ protected:
switch (colType_)
{
case xmlAccess::FULL_PATH:
- value = zToWx(linkObj.getFullName<side>().BeforeLast(common::FILE_NAME_SEPARATOR));
+ value = toWx(linkObj.getFullName<side>().BeforeLast(FILE_NAME_SEPARATOR));
break;
case xmlAccess::FILENAME: //filename
- value = zToWx(linkObj.getShortName<side>());
+ value = toWx(linkObj.getShortName<side>());
break;
case xmlAccess::REL_PATH: //relative path
- value = zToWx(linkObj.getParentRelativeName());
+ value = toWx(linkObj.getParentRelativeName());
break;
case xmlAccess::DIRECTORY:
- value = zToWx(linkObj.getBaseDirPf<side>());
+ value = toWx(linkObj.getBaseDirPf<side>());
break;
case xmlAccess::SIZE: //file size
value = _("<Symlink>");
@@ -339,16 +338,16 @@ protected:
switch (colType_)
{
case xmlAccess::FULL_PATH:
- value = zToWx(dirObj.getFullName<side>());
+ value = toWx(dirObj.getFullName<side>());
break;
case xmlAccess::FILENAME:
- value = zToWx(dirObj.getShortName<side>());
+ value = toWx(dirObj.getShortName<side>());
break;
case xmlAccess::REL_PATH:
- value = zToWx(dirObj.getParentRelativeName());
+ value = toWx(dirObj.getParentRelativeName());
break;
case xmlAccess::DIRECTORY:
- value = zToWx(dirObj.getBaseDirPf<side>());
+ value = toWx(dirObj.getBaseDirPf<side>());
break;
case xmlAccess::SIZE: //file size
value = _("<Directory>");
@@ -1264,7 +1263,8 @@ public:
icon = IconBuffer::getFileIcon(); //better than nothing
}
- dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY());
+ if (icon.IsOk())
+ dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY());
//-----------------------------------------------------------------------------------------------
//save status of last icon load -> used for async. icon loading
@@ -1374,20 +1374,20 @@ void CustomGridRim::setTooltip(const wxMouseEvent& event)
virtual void visit(const FileMapping& fileObj)
{
- tipMsg_ = zToWx(fileObj.getRelativeName<side>()) + wxT("\n") +
- _("Size") + wxT(": ") + zen::formatFilesizeToShortString(fileObj.getFileSize<side>()) + wxT("\n") +
- _("Date") + wxT(": ") + zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
+ tipMsg_ = toWx(fileObj.getRelativeName<side>()) + "\n" +
+ _("Size") + ": " + zen::formatFilesizeToShortString(fileObj.getFileSize<side>()) + "\n" +
+ _("Date") + ": " + zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
}
virtual void visit(const SymLinkMapping& linkObj)
{
- tipMsg_ = zToWx(linkObj.getRelativeName<side>()) + wxT("\n") +
- _("Date") + wxT(": ") + zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
+ tipMsg_ = toWx(linkObj.getRelativeName<side>()) + "\n" +
+ _("Date") + ": " + zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
}
virtual void visit(const DirMapping& dirObj)
{
- tipMsg_ = zToWx(dirObj.getRelativeName<side>());
+ tipMsg_ = toWx(dirObj.getRelativeName<side>());
}
wxString& tipMsg_;
diff --git a/library/db_file.cpp b/library/db_file.cpp
index 1d48dbdf..ec1c4464 100644
--- a/library/db_file.cpp
+++ b/library/db_file.cpp
@@ -30,10 +30,29 @@ namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 6;
+const int FILE_FORMAT_VER = 7;
//-------------------------------------------------------------------------------------------------------------------------------
+template <SelectedSide side> inline
+Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
+{
+ //Linux and Windows builds are binary incompatible: char/wchar_t case, sensitive/insensitive
+ //32 and 64 bit db files ARE designed to be binary compatible!
+ //Give db files different names.
+ //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories
+#ifdef FFS_WIN
+ Zstring dbname = Zstring(Zstr("sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
+#elif defined FFS_LINUX
+ //files beginning with dots are hidden e.g. in Nautilus
+ Zstring dbname = Zstring(Zstr(".sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
+#endif
+
+ return baseMap.getBaseDir<side>() + dbname;
+}
+
+
+
class FileInputStreamDB : public FileInputStream
{
public:
@@ -45,7 +64,7 @@ public:
Read(formatDescr, sizeof(formatDescr)); //throw (FileError)
if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr))
- throw FileError(wxString(_("Incompatible synchronization database format:")) + wxT(" \n") + wxT("\"") + zToWx(filename) + wxT("\""));
+ throw FileError(_("Incompatible synchronization database format:") + " \n" + "\"" + filename + "\"");
}
private:
@@ -138,115 +157,162 @@ private:
namespace
{
typedef std::string UniqueId;
-typedef std::shared_ptr<std::vector<char> > MemoryStreamPtr; //byte stream representing DirInformation
-typedef std::map<UniqueId, MemoryStreamPtr> DirectoryTOC; //list of streams ordered by a UUID pointing to their partner database
-typedef std::pair<UniqueId, DirectoryTOC> DbStreamData; //header data: UUID representing this database, item data: list of dir-streams
+typedef std::shared_ptr<std::vector<char> > MemoryStreamPtr; //byte stream representing DirInformation
+typedef std::map<UniqueId, MemoryStreamPtr> StreamMapping; //list of streams ordered by session UUID
}
-/* Example
-left side right side
---------- ----------
-DB-ID 123 <-\ /-> DB-ID 567
- \/
-Partner-ID 111 /\ Partner-ID 222
-Partner-ID 567 _/ \_ Partner-ID 123
- ... ...
-*/
class ReadFileStream : public zen::ReadInputStream
{
public:
- ReadFileStream(wxInputStream& stream, const wxString& filename, DbStreamData& output, int& versionId) : ReadInputStream(stream, filename)
+ ReadFileStream(wxInputStream& stream, const wxString& filename, StreamMapping& streamList, bool leftSide) : ReadInputStream(stream, filename)
{
//|-------------------------------------------------------------------------------------
//| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t |
//|-------------------------------------------------------------------------------------
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();
- output.first.assign(tmp->begin(), tmp->end());
+#ifndef _MSC_VER
+#warning remove this check after migration!
+#endif
+ if (version != 6) //migrate!
+
+ if (version != FILE_FORMAT_VER) //read file format version
+ throw FileError(_("Incompatible synchronization database format:") + " \n" + "\"" + filename.c_str() + "\"");
+
- DirectoryTOC& dbList = output.second;
- dbList.clear();
+#ifndef _MSC_VER
+#warning remove this case after migration!
+#endif
- boost::uint32_t dbCount = readNumberC<boost::uint32_t>(); //number of databases: one for each sync-pair
- while (dbCount-- != 0)
+ if (version == 6)
{
- //DB id of partner databases
- const CharArray tmp2 = readArrayC();
- const std::string partnerID(tmp2->begin(), tmp2->end());
+ streamList.clear();
+
+ //read DB id
+ const CharArray tmp = readArrayC();
+ std::string mainId(tmp->begin(), tmp->end());
+
+ boost::uint32_t dbCount = readNumberC<boost::uint32_t>(); //number of databases: one for each sync-pair
+ while (dbCount-- != 0)
+ {
+ //DB id of partner databases
+ const CharArray tmp2 = readArrayC();
+ const std::string partnerID(tmp2->begin(), tmp2->end());
- CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation)
+ CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation)
- dbList.insert(std::make_pair(partnerID, buffer));
+ if (leftSide)
+ streamList.insert(std::make_pair(partnerID + mainId, buffer));
+ else
+ streamList.insert(std::make_pair(mainId + partnerID, buffer));
+ }
+ }
+ else
+ {
+ streamList.clear();
+
+ boost::uint32_t dbCount = readNumberC<boost::uint32_t>(); //number of databases: one for each sync-pair
+ while (dbCount-- != 0)
+ {
+ //DB id of partner databases
+ const CharArray tmp2 = readArrayC();
+ const std::string sessionID(tmp2->begin(), tmp2->end());
+
+ CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation)
+
+ streamList.insert(std::make_pair(sessionID, buffer));
+ }
}
}
};
+namespace
+{
+StreamMapping loadStreams(const Zstring& filename,
-DbStreamData loadFile(const Zstring& filename) //throw (FileError)
+#ifndef _MSC_VER
+#warning remove this parameter after migration!
+#endif
+ bool leftSide) //throw (FileError)
{
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("\""));
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + " \n\n" +
+ _("One of the FreeFileSync database files is not yet existing:") + " \n" +
+ "\"" + filename + "\"");
- //read format description (uncompressed)
- FileInputStreamDB uncompressed(filename); //throw (FileError)
+ try
+ {
+ //read format description (uncompressed)
+ FileInputStreamDB uncompressed(filename); //throw (FileError)
- wxZlibInputStream input(uncompressed, wxZLIB_ZLIB);
+ wxZlibInputStream input(uncompressed, wxZLIB_ZLIB);
- DbStreamData output;
- int versionId = 0;
- ReadFileStream (input, zToWx(filename), output, versionId);
- return output;
+ StreamMapping streamList;
+ ReadFileStream(input, toWx(filename), streamList, leftSide);
+ return streamList;
+ }
+ catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
+ {
+ throw FileError(_("Error reading from synchronization database:") + " (bad_alloc)");
+ }
}
-std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw (FileError)
+DirInfoPtr parseStream(const std::vector<char>& stream, const Zstring& fileName) //throw FileError -> return value always bound!
{
- const Zstring fileNameLeft = baseMapping.getDBFilename<LEFT_SIDE>();
- const Zstring fileNameRight = baseMapping.getDBFilename<RIGHT_SIDE>();
-
try
{
- //read file data: db ID + mapping of partner-ID/DirInfo-stream
- const DbStreamData dbEntriesLeft = ::loadFile(fileNameLeft);
- const DbStreamData dbEntriesRight = ::loadFile(fileNameRight);
-
- //find associated DirInfo-streams
- DirectoryTOC::const_iterator dbLeft = dbEntriesLeft.second.find(dbEntriesRight.first); //find left db-entry that corresponds to right database
- DirectoryTOC::const_iterator dbRight = dbEntriesRight.second.find(dbEntriesLeft.first); //find left db-entry that corresponds to right database
-
- if (dbLeft == dbEntriesLeft.second.end())
- throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
- _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") +
- wxT("\"") + zToWx(fileNameLeft) + wxT("\""));
+ //read streams into DirInfo
+ auto dirInfo = std::make_shared<DirInformation>();
+ wxMemoryInputStream buffer(&stream[0], stream.size()); //convert char-array to inputstream: no copying, ownership not transferred
+ ReadDirInfo(buffer, toWx(fileName), *dirInfo); //throw FileError
+ return dirInfo;
+ }
+ catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
+ {
+ throw FileError(_("Error reading from synchronization database:") + " (bad_alloc)");
+ }
+}
+}
- if (dbRight == dbEntriesRight.second.end())
- throw FileErrorDatabaseNotExisting(wxString(_("Initial synchronization:")) + wxT(" \n\n") +
- _("One of the FreeFileSync database entries within the following file is not yet existing:") + wxT(" \n") +
- wxT("\"") + zToWx(fileNameRight) + wxT("\""));
- //read streams into DirInfo
- std::shared_ptr<DirInformation> dirInfoLeft(new DirInformation);
- wxMemoryInputStream buffer(&(*dbLeft->second)[0], dbLeft->second->size()); //convert char-array to inputstream: no copying, ownership not transferred
- ReadDirInfo(buffer, zToWx(fileNameLeft), *dirInfoLeft); //read file/dir information
+std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw (FileError)
+{
+ const Zstring fileNameLeft = getDBFilename<LEFT_SIDE>(baseMapping);
+ const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
- std::shared_ptr<DirInformation> dirInfoRight(new DirInformation);
- wxMemoryInputStream buffer2(&(*dbRight->second)[0], dbRight->second->size()); //convert char-array to inputstream: no copying, ownership not transferred
- ReadDirInfo(buffer2, zToWx(fileNameRight), *dirInfoRight); //read file/dir information
+ //read file data: list of session ID + DirInfo-stream
+ const StreamMapping streamListLeft = ::loadStreams(fileNameLeft, true); //throw (FileError)
+ const StreamMapping streamListRight = ::loadStreams(fileNameRight, false); //throw (FileError)
- return std::make_pair(dirInfoLeft, dirInfoRight);
- }
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
+ //find associated session: there can be at most one session within intersection of left and right ids
+ StreamMapping::const_iterator streamLeft = streamListLeft .end();
+ StreamMapping::const_iterator streamRight = streamListRight.end();
+ for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
{
- throw FileError(wxString(_("Error reading from synchronization database:")) + wxT(" (bad_alloc)"));
+ auto iterRight = streamListRight.find(iterLeft->first);
+ if (iterRight != streamListRight.end())
+ {
+ streamLeft = iterLeft;
+ streamRight = iterRight;
+ break;
+ }
}
+
+ if (streamLeft == streamListLeft .end() ||
+ streamRight == streamListRight.end() ||
+ !streamLeft ->second.get() ||
+ !streamRight->second.get())
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + " \n\n" +
+ _("No matching synchronization session found in database files:") + " \n" +
+ "\"" + fileNameLeft + "\"\n" +
+ "\"" + fileNameRight + "\"");
+ //read streams into DirInfo
+ DirInfoPtr dirInfoLeft = parseStream(*streamLeft ->second, fileNameLeft); //throw FileError
+ DirInfoPtr dirInfoRight = parseStream(*streamRight->second, fileNameRight); //throw FileError
+
+ return std::make_pair(dirInfoLeft, dirInfoRight);
}
@@ -375,21 +441,16 @@ private:
class WriteFileStream : public WriteOutputStream
{
public:
- WriteFileStream(const DbStreamData& input, const wxString& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream)
+ WriteFileStream(const StreamMapping& streamList, const wxString& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream)
{
//save file format version
writeNumberC<boost::int32_t>(FILE_FORMAT_VER);
- //write DB id
- writeArrayC(std::vector<char>(input.first.begin(), input.first.end()));
-
- const DirectoryTOC& dbList = input.second;
+ writeNumberC<boost::uint32_t>(static_cast<boost::uint32_t>(streamList.size())); //number of database records: one for each sync-pair
- writeNumberC<boost::uint32_t>(static_cast<boost::uint32_t>(dbList.size())); //number of database records: one for each sync-pair
-
- for (DirectoryTOC::const_iterator i = dbList.begin(); i != dbList.end(); ++i)
+ for (StreamMapping::const_iterator i = streamList.begin(); i != streamList.end(); ++i)
{
- //DB id of partner database
+ //sync session id
writeArrayC(std::vector<char>(i->first.begin(), i->first.end()));
//write DirInformation stream
@@ -400,7 +461,7 @@ public:
//save/load DirContainer
-void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (FileError)
+void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw (FileError)
{
{
//write format description (uncompressed)
@@ -414,7 +475,7 @@ void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (Fi
6 1,77 MB - 613 ms
9 (maximal compression) 1,74 MB - 3330 ms */
- WriteFileStream(dbStream, zToWx(filename), output);
+ WriteFileStream(streamList, toWx(filename), output);
}
//(try to) hide database file
#ifdef FFS_WIN
@@ -423,133 +484,132 @@ void saveFile(const DbStreamData& dbStream, const Zstring& filename) //throw (Fi
}
-bool entryExisting(const DirectoryTOC& table, const UniqueId& newKey, const MemoryStreamPtr& newValue)
+bool equalEntry(const MemoryStreamPtr& lhs, const MemoryStreamPtr& rhs)
{
- DirectoryTOC::const_iterator iter = table.find(newKey);
- if (iter == table.end())
- return false;
-
- if (!newValue.get() || !iter->second.get())
- return newValue.get() == iter->second.get();
+ if (!lhs.get() || !rhs.get())
+ return lhs.get() == rhs.get();
- return *newValue == *iter->second;
+ return *lhs == *rhs;
}
void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw (FileError)
{
//transactional behaviour! write to tmp files first
- const Zstring fileNameLeftTmp = baseMapping.getDBFilename<LEFT_SIDE>() + Zstr(".tmp");
- const Zstring fileNameRightTmp = baseMapping.getDBFilename<RIGHT_SIDE>() + Zstr(".tmp");;
+ const Zstring dbNameLeftTmp = getDBFilename<LEFT_SIDE >(baseMapping, true);
+ const Zstring dbNameRightTmp = getDBFilename<RIGHT_SIDE>(baseMapping, true);
+
+ const Zstring dbNameLeft = getDBFilename<LEFT_SIDE >(baseMapping);
+ const Zstring dbNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
//delete old tmp file, if necessary -> throws if deletion fails!
- removeFile(fileNameLeftTmp); //
- removeFile(fileNameRightTmp); //throw (FileError)
+ removeFile(dbNameLeftTmp); //
+ removeFile(dbNameRightTmp); //throw (FileError)
- //load old database files...
+ //(try to) load old database files...
+ StreamMapping streamListLeft;
+ StreamMapping streamListRight;
- //read file data: db ID + mapping of partner-ID/DirInfo-stream: may throw!
- DbStreamData dbEntriesLeft;
- try
- {
- dbEntriesLeft = ::loadFile(baseMapping.getDBFilename<LEFT_SIDE>());
- }
- catch(FileError&)
+ try //read file data: list of session ID + DirInfo-stream
{
- //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- //dbEntriesLeft has empty mapping, but already a DB-ID!
- dbEntriesLeft.first = util::generateGUID();
+ streamListLeft = ::loadStreams(dbNameLeft, true);
}
-
- //read file data: db ID + mapping of partner-ID/DirInfo-stream: may throw!
- DbStreamData dbEntriesRight;
+ catch(FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
try
{
- dbEntriesRight = ::loadFile(baseMapping.getDBFilename<RIGHT_SIDE>());
+ streamListRight = ::loadStreams(dbNameRight, false);
}
- catch(FileError&)
+ catch(FileError&) {}
+
+ //find associated session: there can be at most one session within intersection of left and right ids
+ StreamMapping::iterator streamLeft = streamListLeft .end();
+ StreamMapping::iterator streamRight = streamListRight.end();
+ for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
{
- dbEntriesRight.first = util::generateGUID();
+ auto iterRight = streamListRight.find(iterLeft->first);
+ if (iterRight != streamListRight.end())
+ {
+ streamLeft = iterLeft;
+ streamRight = iterRight;
+ break;
+ }
}
-
//(try to) read old DirInfo
- std::shared_ptr<DirInformation> oldDirInfoLeft;
+ DirInfoPtr oldDirInfoLeft;
+ DirInfoPtr oldDirInfoRight;
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::shared_ptr<DirInformation> dirInfoTmp = std::make_shared<DirInformation>();
- ReadDirInfo(buffer, zToWx(baseMapping.getDBFilename<LEFT_SIDE>()), *dirInfoTmp); //read file/dir information
- oldDirInfoLeft = dirInfoTmp;
- }
+ if (streamLeft != streamListLeft .end() &&
+ streamRight != streamListRight.end() &&
+ streamLeft ->second.get() &&
+ streamRight->second.get())
+ {
+ oldDirInfoLeft = parseStream(*streamLeft ->second, dbNameLeft); //throw FileError
+ oldDirInfoRight = parseStream(*streamRight->second, dbNameRight); //throw FileError
+ }
}
- catch(FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
-
- std::shared_ptr<DirInformation> oldDirInfoRight;
- try
+ catch(FileError&)
{
- 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::shared_ptr<DirInformation> dirInfoTmp = std::make_shared<DirInformation>();
- ReadDirInfo(buffer, zToWx(baseMapping.getDBFilename<RIGHT_SIDE>()), *dirInfoTmp); //read file/dir information
- oldDirInfoRight = dirInfoTmp;
- }
+ //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
+ oldDirInfoLeft .reset(); //read both or none!
+ oldDirInfoRight.reset(); //
}
- catch(FileError&) {}
-
//create new database entries
- MemoryStreamPtr dbEntryLeft(new std::vector<char>);
+ MemoryStreamPtr newStreamLeft = std::make_shared<std::vector<char>>();
{
wxMemoryOutputStream 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()); //
+ const DirContainer* oldDir = oldDirInfoLeft.get() ? &oldDirInfoLeft->baseDirContainer : NULL;
+ SaveDirInfo<LEFT_SIDE>(baseMapping, oldDir, toWx(dbNameLeft), buffer);
+ newStreamLeft->resize(buffer.GetSize()); //convert output stream to char-array
+ buffer.CopyTo(&(*newStreamLeft)[0], buffer.GetSize()); //
}
- MemoryStreamPtr dbEntryRight(new std::vector<char>);
+ MemoryStreamPtr newStreamRight = std::make_shared<std::vector<char>>();
{
wxMemoryOutputStream 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()); //
+ const DirContainer* oldDir = oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL;
+ SaveDirInfo<RIGHT_SIDE>(baseMapping, oldDir, toWx(dbNameRight), buffer);
+ newStreamRight->resize(buffer.GetSize()); //convert output stream to char-array
+ buffer.CopyTo(&(*newStreamRight)[0], buffer.GetSize()); //
}
- //create/update DirInfo-streams
+ //check if there is some work to do at all
{
- const bool updateRequiredLeft = !entryExisting(dbEntriesLeft. second, dbEntriesRight.first, dbEntryLeft);
- const bool updateRequiredRight = !entryExisting(dbEntriesRight.second, dbEntriesLeft. first, dbEntryRight);
+ const bool updateRequiredLeft = streamLeft == streamListLeft .end() || !equalEntry(newStreamLeft, streamLeft ->second);
+ const bool updateRequiredRight = streamRight == streamListRight.end() || !equalEntry(newStreamRight, streamRight->second);
//some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed
if (!updateRequiredLeft && !updateRequiredRight)
return;
}
- dbEntriesLeft .second[dbEntriesRight.first] = dbEntryLeft;
- dbEntriesRight.second[dbEntriesLeft .first] = dbEntryRight;
+
+ //create/update DirInfo-streams
+ std::string sessionID = util::generateGUID();
+
+ //erase old session data
+ if (streamLeft != streamListLeft.end())
+ streamListLeft.erase(streamLeft);
+ if (streamRight != streamListRight.end())
+ streamListRight.erase(streamRight);
+
+ //fill in new
+ streamListLeft .insert(std::make_pair(sessionID, newStreamLeft));
+ streamListRight.insert(std::make_pair(sessionID, newStreamRight));
//write (temp-) files...
- Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&zen::removeFile, fileNameLeftTmp);
- saveFile(dbEntriesLeft, fileNameLeftTmp); //throw (FileError)
+ Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&zen::removeFile, dbNameLeftTmp);
+ saveFile(streamListLeft, dbNameLeftTmp); //throw (FileError)
- Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&zen::removeFile, fileNameRightTmp);
- saveFile(dbEntriesRight, fileNameRightTmp); //throw (FileError)
+ Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&zen::removeFile, dbNameRightTmp);
+ saveFile(streamListRight, dbNameRightTmp); //throw (FileError)
//operation finished: rename temp files -> this should work transactionally:
//if there were no write access, creation of temp files would have failed
- removeFile(baseMapping.getDBFilename<LEFT_SIDE>());
- removeFile(baseMapping.getDBFilename<RIGHT_SIDE>());
- renameFile(fileNameLeftTmp, baseMapping.getDBFilename<LEFT_SIDE>()); //throw (FileError);
- renameFile(fileNameRightTmp, baseMapping.getDBFilename<RIGHT_SIDE>()); //throw (FileError);
+ removeFile(dbNameLeft);
+ removeFile(dbNameRight);
+ renameFile(dbNameLeftTmp, dbNameLeft); //throw (FileError);
+ renameFile(dbNameRightTmp, dbNameRight); //throw (FileError);
guardTempFileLeft. Dismiss(); //no need to delete temp file anymore
guardTempFileRight.Dismiss(); //
diff --git a/library/db_file.h b/library/db_file.h
index 5c03ee96..a68e6bcf 100644
--- a/library/db_file.h
+++ b/library/db_file.h
@@ -12,6 +12,8 @@
namespace zen
{
+const Zstring SYNC_DB_FILE_ENDING = Zstr(".ffs_db");
+
void saveToDisk(const BaseDirMapping& baseMapping); //throw (FileError)
struct DirInformation
diff --git a/library/dir_lock.cpp b/library/dir_lock.cpp
index 835db4ef..1775026b 100644
--- a/library/dir_lock.cpp
+++ b/library/dir_lock.cpp
@@ -11,7 +11,6 @@
#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"
#include "../shared/guid.h"
#include "../shared/file_io.h"
#include "../shared/assert_static.h"
@@ -47,20 +46,12 @@ const int LOCK_FORMAT_VER = 1; //lock file format version
typedef Zbase<Zchar, StorageDeepCopy> BasicString; //thread safe string class
}
+//worker thread
class LifeSigns
{
public:
LifeSigns(const BasicString& lockfilename) : //throw()!!! siehe SharedDirLock()
- lockfilename_(lockfilename) //thread safety: make deep copy!
- {
- threadObj = boost::thread(boost::cref(*this)); //localize all thread logic to this class!
- }
-
- ~LifeSigns()
- {
- threadObj.interrupt(); //thread lifetime is subset of this instances's life
- threadObj.join();
- }
+ lockfilename_(lockfilename) {} //thread safety: make deep copy!
void operator()() const //thread entry
{
@@ -129,11 +120,8 @@ public:
}
private:
- LifeSigns(const LifeSigns&); //just be sure this ref-counting Zstring doesn't bite
- LifeSigns& operator=(const LifeSigns&); //
-
- boost::thread threadObj;
- const BasicString lockfilename_; //used by worker thread only! Not ref-counted!
+ //make sure this instance is safely copyable!
+ const BasicString lockfilename_; //thread local! Not ref-counted!
};
@@ -147,8 +135,7 @@ void deleteLockFile(const Zstring& filename) //throw (FileError)
if (::unlink(filename.c_str()) != 0)
#endif
{
- wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\"");
- throw FileError(errorMessage + wxT("\n\n") + getLastErrorFormatted());
+ throw FileError(_("Error deleting file:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted());
}
}
@@ -162,8 +149,7 @@ zen::UInt64 getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo
{
const DWORD lastError = ::GetLastError();
- wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"");
- errorMessage += wxT("\n\n") + getLastErrorFormatted(lastError);
+ std::wstring errorMessage = _("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted(lastError);
if (lastError == ERROR_FILE_NOT_FOUND ||
lastError == ERROR_PATH_NOT_FOUND)
@@ -182,8 +168,7 @@ zen::UInt64 getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo
{
const int lastError = errno;
- wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(filename) + wxT("\"");
- errorMessage += wxT("\n\n") + getLastErrorFormatted(lastError);
+ std::wstring errorMessage = _("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted(lastError);
if (lastError == ENOENT)
throw ErrorNotExisting(errorMessage);
@@ -196,13 +181,13 @@ zen::UInt64 getLockFileSize(const Zstring& filename) //throw (FileError, ErrorNo
}
-Zstring deleteAbandonedLockName(const Zstring& lockfilename)
+Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT change file ending!
{
- const size_t pos = lockfilename.rfind(common::FILE_NAME_SEPARATOR); //search from end
+ const size_t pos = lockfilename.rfind(FILE_NAME_SEPARATOR); //search from end
return pos == Zstring::npos ? Zstr("Del.") + lockfilename :
Zstring(lockfilename.c_str(), pos + 1) + //include path separator
Zstr("Del.") +
- lockfilename.AfterLast(common::FILE_NAME_SEPARATOR); //returns the whole string if ch not found
+ lockfilename.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if ch not found
}
@@ -319,6 +304,7 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
0); //__in DWORD th32ProcessID
if (snapshot == INVALID_HANDLE_VALUE)
return PROC_STATUS_NO_IDEA;
+
Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, snapshot);
(void)dummy; //silence warning "unused variable"
@@ -371,10 +357,10 @@ std::string retrieveLockId(const Zstring& lockfilename) //throw (FileError, Erro
void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw (FileError)
{
- Zstring infoMsg;
- infoMsg = wxToZ(_("Waiting while directory is locked (%x)..."));
- infoMsg.Replace(Zstr("%x"), Zstr("\"") + lockfilename + Zstr("\""));
- if (callback) callback->reportInfo(infoMsg);
+ std::wstring infoMsg = _("Waiting while directory is locked (%x)...");
+ replace(infoMsg, L"%x", std::wstring(L"\"") + lockfilename + "\"");
+ if (callback)
+ callback->reportInfo(infoMsg);
//---------------------------------------------------------------
try
{
@@ -428,16 +414,15 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr
long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong();
remainingSeconds = std::max(0L, remainingSeconds);
- Zstring remSecMsg = wxToZ(_P("1 sec", "%x sec", remainingSeconds));
- remSecMsg.Replace(Zstr("%x"), Zstring::fromNumber(remainingSeconds));
- callback->reportInfo(infoMsg + Zstr(" ") + remSecMsg);
+ std::wstring remSecMsg = _P("1 sec", "%x sec", remainingSeconds);
+ replace(remSecMsg, L"%x", toString<std::wstring>(remainingSeconds));
+ callback->reportInfo(infoMsg + " " + remSecMsg);
}
else
callback->reportInfo(infoMsg); //emit a message in any case (might clear other one)
}
}
}
-
}
catch (const ErrorNotExisting&)
{
@@ -471,10 +456,7 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError)
if (::GetLastError() == ERROR_FILE_EXISTS)
return false;
else
- {
- wxString errorMessage = wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"");
- throw FileError(errorMessage + wxT("\n\n") + getLastErrorFormatted());
- }
+ throw FileError(_("Error setting directory lock:") + "\n\"" + lockfilename + "\"" + "\n\n" + getLastErrorFormatted());
}
::CloseHandle(fileHandle);
@@ -487,11 +469,7 @@ bool tryLock(const Zstring& lockfilename) //throw (FileError)
if (errno == EEXIST)
return false;
else
- {
- wxString errorMessage = wxString(_("Error setting directory lock:")) + wxT("\n\"") + zToWx(lockfilename) + wxT("\"");
- throw FileError(errorMessage + wxT("\n\n") + getLastErrorFormatted());
- }
-
+ throw FileError(_("Error setting directory lock:") + "\n\"" + lockfilename + "\"" + "\n\n" + getLastErrorFormatted());
}
::close(fileHandle);
#endif
@@ -516,12 +494,13 @@ public:
while (!::tryLock(lockfilename)) //throw (FileError)
::waitOnDirLock(lockfilename, callback); //
- emitLifeSigns.reset(new LifeSigns(lockfilename.c_str())); //throw()! ownership of lockfile not yet managed!
+ threadObj = boost::thread(LifeSigns(lockfilename.c_str()));
}
~SharedDirLock()
{
- emitLifeSigns.reset();
+ threadObj.interrupt(); //thread lifetime is subset of this instances's life
+ threadObj.join();
::releaseLock(lockfilename_); //throw ()
}
@@ -532,7 +511,7 @@ private:
const Zstring lockfilename_;
- std::auto_ptr<LifeSigns> emitLifeSigns;
+ boost::thread threadObj;
};
diff --git a/library/dir_lock.h b/library/dir_lock.h
index 5d51d698..f4720e61 100644
--- a/library/dir_lock.h
+++ b/library/dir_lock.h
@@ -1,7 +1,6 @@
#ifndef DIR_LOCK_H_INCLUDED
#define DIR_LOCK_H_INCLUDED
-#include "../shared/zstring.h"
#include "../shared/file_error.h"
#include <memory>
@@ -10,7 +9,7 @@ struct DirLockCallback //while waiting for the lock
{
virtual ~DirLockCallback() {}
virtual void requestUiRefresh() = 0; //allowed to throw exceptions
- virtual void reportInfo(const Zstring& text) = 0;
+ virtual void reportInfo(const std::wstring& text) = 0;
};
/*
diff --git a/library/error_log.cpp b/library/error_log.cpp
index a78b1c9a..eef8572a 100644
--- a/library/error_log.cpp
+++ b/library/error_log.cpp
@@ -73,14 +73,19 @@ wxString ErrorLogging::formatMessage(const Entry& msg)
break;
}
- const wxString prefix = wxString(wxT("[")) + wxDateTime(msg.time).FormatTime() + wxT("] ") + typeName + wxT(": ");
+ const wxString prefix = wxString(L"[") + wxDateTime(msg.time).FormatTime() + L"] " + typeName + L": ";
wxString formattedText = prefix;
- for (wxString::const_iterator i = msg.message.begin(); i != msg.message.end(); ++i)
+ for (auto i = msg.message.begin(); i != msg.message.end(); ++i)
if (*i == wxChar('\n'))
{
- formattedText += wxString(wxChar('\n')).Pad(prefix.size(), wxChar(' '), true);
- while (*++i == wxChar('\n')) //remove duplicate newlines
+ formattedText += L'\n';
+
+ wxString blanks;
+ blanks.resize(prefix.size(), L' ');
+ formattedText += blanks;
+
+ while (*++i == L'\n') //remove duplicate newlines
;
--i;
}
diff --git a/library/error_log.h b/library/error_log.h
index 1acc0f8c..323a4297 100644
--- a/library/error_log.h
+++ b/library/error_log.h
@@ -10,7 +10,6 @@
#include <wx/string.h>
#include <vector>
#include <map>
-#include "../shared/zstring.h"
namespace zen
@@ -37,7 +36,7 @@ private:
{
MessageType type;
time_t time;
- wxString message;
+ wxString message;
};
static wxString formatMessage(const Entry& msg);
diff --git a/library/hard_filter.cpp b/library/hard_filter.cpp
index 194fe41c..e96d32fa 100644
--- a/library/hard_filter.cpp
+++ b/library/hard_filter.cpp
@@ -10,7 +10,6 @@
#include <set>
#include <stdexcept>
#include <vector>
-#include "../shared/system_constants.h"
#include "../structures.h"
#include <boost/bind.hpp>
#include "../shared/loki/LokiTypeInfo.h"
@@ -58,7 +57,6 @@ HardFilter::FilterRef HardFilter::loadFilter(wxInputStream& stream)
//--------------------------------------------------------------------------------------------------
-inline
void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, std::set<Zstring>& directoryFilter)
{
Zstring filterFormatted = filtername;
@@ -70,17 +68,17 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st
//Linux DOES distinguish between upper/lower-case: nothing to do here
#endif
- 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;
+ const Zstring sepAsterisk = Zstring(FILE_NAME_SEPARATOR) + Zchar('*');
+ const Zstring sepQuestionMark = Zstring(FILE_NAME_SEPARATOR) + Zchar('?');
+ const Zstring asteriskSep = Zstring(Zstr('*')) + FILE_NAME_SEPARATOR;
+ const Zstring questionMarkSep = Zstring(Zstr('?')) + FILE_NAME_SEPARATOR;
//--------------------------------------------------------------------------------------------------
//add some syntactic sugar: handle beginning of filtername
- if (filterFormatted.StartsWith(common::FILE_NAME_SEPARATOR))
+ if (filterFormatted.StartsWith(FILE_NAME_SEPARATOR))
{
//remove leading separators (keep BEFORE test for Zstring::empty()!)
- filterFormatted = filterFormatted.AfterFirst(common::FILE_NAME_SEPARATOR);
+ filterFormatted = filterFormatted.AfterFirst(FILE_NAME_SEPARATOR);
}
else if (filterFormatted.StartsWith(asteriskSep) || // *\abc
filterFormatted.StartsWith(questionMarkSep)) // ?\abc
@@ -90,9 +88,9 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st
//--------------------------------------------------------------------------------------------------
//even more syntactic sugar: handle end of filtername
- if (filterFormatted.EndsWith(common::FILE_NAME_SEPARATOR))
+ if (filterFormatted.EndsWith(FILE_NAME_SEPARATOR))
{
- const Zstring candidate = filterFormatted.BeforeLast(common::FILE_NAME_SEPARATOR);
+ const Zstring candidate = filterFormatted.BeforeLast(FILE_NAME_SEPARATOR);
if (!candidate.empty())
directoryFilter.insert(candidate); //only relevant for directory filtering
}
@@ -102,7 +100,7 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st
fileFilter.insert( filterFormatted);
directoryFilter.insert(filterFormatted);
- const Zstring candidate = filterFormatted.BeforeLast(common::FILE_NAME_SEPARATOR);
+ const Zstring candidate = filterFormatted.BeforeLast(FILE_NAME_SEPARATOR);
if (!candidate.empty())
directoryFilter.insert(candidate); //only relevant for directory filtering
}
@@ -235,19 +233,20 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString)
//delimiters may be ';' or '\n'
std::vector<Zstring> output;
- 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> blocks = split(filterString, Zchar(';'));
+ std::for_each(blocks.begin(), blocks.end(),
+ [&](const Zstring& item)
{
- const std::vector<Zstring> blocks2 = i->Split(Zchar('\n'));
+ const std::vector<Zstring> blocks2 = split(item, Zchar('\n'));
- for (std::vector<Zstring>::const_iterator j = blocks2.begin(); j != blocks2.end(); ++j)
+ std::for_each(blocks2.begin(), blocks2.end(),
+ [&](Zstring entry)
{
- Zstring entry = *j;
- entry.Trim();
+ trim(entry);
if (!entry.empty())
output.push_back(entry);
- }
- }
+ });
+ });
return output;
}
@@ -261,12 +260,12 @@ NameFilter::NameFilter(const Zstring& includeFilter, const Zstring& excludeFilte
//load filter into vectors of strings
//delimiters may be ';' or '\n'
- const std::vector<Zstring> includeList = compoundStringToFilter(includeFilter);
- const std::vector<Zstring> excludeList = compoundStringToFilter(excludeFilter);
+ const std::vector<Zstring>& includeList = compoundStringToFilter(includeFilter);
+ const std::vector<Zstring>& excludeList = compoundStringToFilter(excludeFilter);
//setup include/exclude filters for files and directories
- std::for_each(includeList.begin(), includeList.end(), boost::bind(addFilterEntry, _1, boost::ref(filterFileIn), boost::ref(filterFolderIn)));
- std::for_each(excludeList.begin(), excludeList.end(), boost::bind(addFilterEntry, _1, boost::ref(filterFileEx), boost::ref(filterFolderEx)));
+ std::for_each(includeList.begin(), includeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileIn, filterFolderIn); });
+ std::for_each(excludeList.begin(), excludeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileEx, filterFolderEx); });
}
@@ -306,7 +305,7 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch
{
if (subObjMightMatch)
{
- const Zstring& subNameBegin = nameFormatted + common::FILE_NAME_SEPARATOR; //const-ref optimization
+ const Zstring& subNameBegin = nameFormatted + FILE_NAME_SEPARATOR; //const-ref optimization
*subObjMightMatch = matchesFilterBegin(subNameBegin, filterFileIn) || //might match a file in subdirectory
matchesFilterBegin(subNameBegin, filterFolderIn); //or another subdirectory
diff --git a/library/icon_buffer.cpp b/library/icon_buffer.cpp
index 1b1706d2..91487498 100644
--- a/library/icon_buffer.cpp
+++ b/library/icon_buffer.cpp
@@ -26,8 +26,6 @@
using namespace zen;
-
-
const size_t BUFFER_SIZE_MAX = 800; //maximum number of icons to buffer
//---------------------------------------------------------------------------------------------------
@@ -80,7 +78,7 @@ public:
IconHolder(HandleType handle = 0) : handle_(handle) {} //take ownership!
//icon holder has value semantics!
- IconHolder(const IconHolder& other) : handle_(other.handle_ == 0 ? 0 :
+ IconHolder(const IconHolder& other) : handle_(other.handle_ == NULL ? NULL :
#ifdef FFS_WIN
::CopyIcon(other.handle_)
#elif defined FFS_LINUX
@@ -96,7 +94,7 @@ public:
~IconHolder()
{
- if (handle_ != 0)
+ if (handle_ != NULL)
#ifdef FFS_WIN
::DestroyIcon(handle_);
#elif defined FFS_LINUX
@@ -111,7 +109,7 @@ public:
wxIcon toWxIcon() const //copy HandleType, caller needs to take ownership!
{
- if (handle_ == 0)
+ if (handle_ == NULL)
return wxNullIcon;
IconHolder clone(*this);
@@ -123,7 +121,7 @@ public:
#elif defined FFS_LINUX //
newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
#endif //
- clone.handle_ = 0; //
+ clone.handle_ = NULL; //
return newIcon;
}
@@ -213,7 +211,7 @@ IconHolder getAssociatedIconByExt(const BasicString& extension)
#endif
-const wxIcon& getDirectoryIcon() //one folder icon should be sufficient...
+const wxIcon& getDirectoryIcon()
{
static wxIcon folderIcon;
@@ -246,7 +244,7 @@ const wxIcon& getDirectoryIcon() //one folder icon should be sufficient...
}
-const wxIcon& getFileIcon() //in case one folder icon is sufficient...
+const wxIcon& getFileIcon()
{
static wxIcon fileIcon;
@@ -292,128 +290,87 @@ const wxIcon& getFileIcon() //in case one folder icon is sufficient...
//################################################################################################################################################
-class Buffer
+//---------------------- Shared Data -------------------------
+struct WorkLoad
{
-public:
- //methods used by gui and worker thread
- bool requestFileIcon(const Zstring& fileName, wxIcon* icon = NULL);
+ std::vector<BasicString> filesToLoad; //processes last elements of vector first!
+ boost::mutex mutex;
+ boost::condition_variable condition; //signal event: data for processing available
+};
- //methods used by worker thread
- void insertIntoBuffer(const BasicString& entryName, const IconHolder& icon);
+typedef std::map<BasicString, IconHolder, LessFilename> NameIconMap; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure!
+typedef std::queue<BasicString> IconDbSequence; //entryName
-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
- //---------------------------------------------------------------------------------------------------
-
- //---------------------- Shared Data -------------------------
- boost::mutex lockIconDB;
- IconDB iconBuffer; //use synchronisation when accessing this!
+struct Buffer
+{
+ boost::mutex lockAccess;
+ NameIconMap iconMappping; //use synchronisation when accessing this!
IconDbSequence iconSequence; //save sequence of buffer entry to delete oldest elements
- //------------------------------------------------------------
};
+//------------------------------------------------------------
-bool Buffer::requestFileIcon(const Zstring& fileName, wxIcon* icon)
+bool requestFileIcon(Buffer& buf, const Zstring& fileName, wxIcon* icon = NULL)
{
- boost::lock_guard<boost::mutex> dummy(lockIconDB);
+ boost::lock_guard<boost::mutex> dummy(buf.lockAccess);
#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);
+ const BasicString extension = getFileExtension(BasicString(fileName));
+ const BasicString searchString = isPriceyExtension(extension) ? BasicString(fileName) : extension;
+ auto iter = buf.iconMappping.find(searchString);
#elif defined FFS_LINUX
- IconDB::const_iterator i = iconBuffer.find(fileName.c_str());
+ auto iter = buf.iconMappping.find(BasicString(fileName));
#endif
- if (i == iconBuffer.end())
+ if (iter == buf.iconMappping.end())
return false;
if (icon != NULL)
- *icon = i->second.toWxIcon();
-
+ *icon = iter->second.toWxIcon();
return true;
}
-void Buffer::insertIntoBuffer(const BasicString& entryName, const IconHolder& icon) //called by worker thread
+void insertIntoBuffer(Buffer& buf, const BasicString& entryName, const IconHolder& icon) //called by worker thread
{
- boost::lock_guard<boost::mutex> dummy(lockIconDB);
+ boost::lock_guard<boost::mutex> dummy(buf.lockAccess);
//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));
+ auto rc = buf.iconMappping.insert(std::make_pair(entryName, icon));
if (rc.second) //if insertion took place
- iconSequence.push(entryName); //note: sharing Zstring with IconDB!!!
+ buf.iconSequence.push(entryName); //note: sharing Zstring with IconDB!!!
- assert(iconBuffer.size() == iconSequence.size());
+ assert(buf.iconMappping.size() == buf.iconSequence.size());
//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)
+ if (buf.iconMappping.size() > BUFFER_SIZE_MAX) //limit buffer size: critical because GDI resources are limited (e.g. 10000 on XP per process)
{
//remove oldest element
- iconBuffer.erase(iconSequence.front());
- iconSequence.pop();
+ buf.iconMappping.erase(buf.iconSequence.front());
+ buf.iconSequence.pop();
}
}
-
-
//################################################################################################################################################
-class WorkerThread
+
+class WorkerThread //lifetime is part of icon buffer
{
public:
- 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
+ WorkerThread(const std::shared_ptr<WorkLoad>& workload,
+ const std::shared_ptr<Buffer>& buffer) :
+ workload_(workload),
+ buffer_(buffer) {}
void operator()(); //thread entry
private:
void doWork();
- //---------------------- Shared Data -------------------------
- typedef BasicString FileName;
-
- struct SharedData
- {
- std::vector<FileName> workload; //processes last elements of vector first!
- boost::mutex mutex;
- boost::condition_variable condition; //signal event: data for processing available
- } shared;
- //------------------------------------------------------------
-
- Buffer& iconBuffer;
-
- boost::thread threadObj;
+ std::shared_ptr<WorkLoad> workload_;
+ std::shared_ptr<Buffer> buffer_;
};
-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);
-
- shared.workload.clear();
- for (std::vector<Zstring>::const_iterator i = load.begin(); i != load.end(); ++i)
- shared.workload.push_back(FileName(i->c_str(), i->size())); //make DEEP COPY from Zstring
- }
-
- shared.condition.notify_one();
- //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
-}
-
-
void WorkerThread::operator()() //thread entry
{
//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
@@ -430,9 +387,9 @@ void WorkerThread::operator()() //thread entry
while (true)
{
{
- boost::unique_lock<boost::mutex> dummy(shared.mutex);
- while(shared.workload.empty())
- shared.condition.wait(dummy); //interruption point!
+ boost::unique_lock<boost::mutex> dummy(workload_->mutex);
+ while(workload_->filesToLoad.empty())
+ workload_->condition.wait(dummy); //interruption point!
//shared.condition.timed_wait(dummy, boost::get_system_time() + boost::posix_time::milliseconds(100));
}
@@ -461,14 +418,14 @@ void WorkerThread::doWork()
{
BasicString fileName;
{
- boost::lock_guard<boost::mutex> dummy(shared.mutex);
- if (shared.workload.empty())
+ boost::lock_guard<boost::mutex> dummy(workload_->mutex);
+ if (workload_->filesToLoad.empty())
break; //enter waiting state
- fileName = shared.workload.back(); //deep copy
- shared.workload.pop_back();
+ fileName = workload_->filesToLoad.back(); //deep copy
+ workload_->filesToLoad.pop_back();
}
- if (iconBuffer.requestFileIcon(fileName.c_str())) //thread safety: Zstring okay, won't be reference-counted in requestIcon()
+ if (requestFileIcon(*buffer_, Zstring(fileName))) //thread safety: Zstring okay, won't be reference-counted in requestIcon()
continue; //icon already in buffer: skip
#ifdef FFS_WIN
@@ -476,16 +433,16 @@ void WorkerThread::doWork()
if (isPriceyExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
{
const IconHolder newIcon = getAssociatedIcon(fileName);
- iconBuffer.insertIntoBuffer(fileName, newIcon);
+ insertIntoBuffer(*buffer_, fileName, newIcon);
}
else //no read-access to disk! determine icon by extension
{
const IconHolder newIcon = getAssociatedIconByExt(extension);
- iconBuffer.insertIntoBuffer(extension, newIcon);
+ insertIntoBuffer(*buffer_, extension, newIcon);
}
#elif defined FFS_LINUX
const IconHolder newIcon = getAssociatedIcon(fileName);
- iconBuffer.insertIntoBuffer(fileName, newIcon);
+ insertIntoBuffer(*buffer_, fileName, newIcon);
#endif
}
}
@@ -495,16 +452,30 @@ void WorkerThread::doWork()
struct IconBuffer::Pimpl
{
- Pimpl() : buffer(), worker(buffer) {} //might throw exceptions!
+ Pimpl() :
+ workload(std::make_shared<WorkLoad>()),
+ buffer(std::make_shared<Buffer>()) {}
+
+
+ std::shared_ptr<WorkLoad> workload;
+ std::shared_ptr<Buffer> buffer;
- Buffer buffer;
- WorkerThread worker;
+ boost::thread worker;
};
-IconBuffer::IconBuffer() : pimpl(new Pimpl) {}
+IconBuffer::IconBuffer() : pimpl(new Pimpl)
+{
+ pimpl->worker = boost::thread(WorkerThread(pimpl->workload, pimpl->buffer));
+}
+
-IconBuffer::~IconBuffer() {} //auto_ptr<>: keep destructor non-inline
+IconBuffer::~IconBuffer()
+{
+ setWorkload(std::vector<Zstring>()); //make sure interruption point is always reached!
+ pimpl->worker.interrupt();
+ pimpl->worker.join();
+}
const wxIcon& IconBuffer::getDirectoryIcon() { return ::getDirectoryIcon(); }
@@ -516,6 +487,19 @@ IconBuffer& IconBuffer::getInstance()
return instance;
}
-bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon) { return pimpl->buffer.requestFileIcon(fileName, icon); }
+bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon) { return ::requestFileIcon(*pimpl->buffer, fileName, icon); }
+
+void IconBuffer::setWorkload(const std::vector<Zstring>& load)
+{
+ {
+ boost::lock_guard<boost::mutex> dummy(pimpl->workload->mutex);
-void IconBuffer::setWorkload(const std::vector<Zstring>& load) { return pimpl->worker.setWorkload(load); }
+ pimpl->workload->filesToLoad.clear();
+
+ std::transform(load.begin(), load.end(), std::back_inserter(pimpl->workload->filesToLoad),
+ [](const Zstring& file) { return BasicString(file); }); //make DEEP COPY from Zstring
+ }
+
+ pimpl->workload->condition.notify_one();
+ //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
+}
diff --git a/library/icon_buffer.h b/library/icon_buffer.h
index 5ab2740c..87f0cd4a 100644
--- a/library/icon_buffer.h
+++ b/library/icon_buffer.h
@@ -17,7 +17,7 @@ namespace zen
class IconBuffer
{
public:
- static const wxIcon& getDirectoryIcon(); //one icon should be sufficient...
+ static const wxIcon& getDirectoryIcon(); //generic icons
static const wxIcon& getFileIcon(); //
static IconBuffer& getInstance();
@@ -35,7 +35,7 @@ private:
~IconBuffer();
struct Pimpl;
- std::auto_ptr<Pimpl> pimpl;
+ std::unique_ptr<Pimpl> pimpl;
};
}
diff --git a/library/lock_holder.h b/library/lock_holder.h
index 38323695..dc88ce71 100644
--- a/library/lock_holder.h
+++ b/library/lock_holder.h
@@ -8,7 +8,7 @@
namespace zen
{
-const Zstring LOCK_FILE_ENDING = Zstr("ffs_lock"); //intermediate locks created by DirLock use this extension, too!
+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
@@ -18,21 +18,21 @@ public:
{
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
+ assert(dirnameFmt.EndsWith(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); }
+ virtual void reportInfo(const std::wstring& text) { pc_.reportInfo(text); }
private:
ProcessCallback& pc_;
} callback(procCallback);
try
{
- lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync.") + LOCK_FILE_ENDING, &callback)));
+ lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback)));
}
catch (const FileError& e)
{
diff --git a/library/process_xml.cpp b/library/process_xml.cpp
index 1b5f6360..69dad7f3 100644
--- a/library/process_xml.cpp
+++ b/library/process_xml.cpp
@@ -88,6 +88,7 @@ void xmlAccess::OptionalDialogs::resetDialogs()
warningNotEnoughDiskSpace = true;
warningUnresolvedConflicts = true;
warningSyncDatabase = true;
+ warningRecyclerMissing = true;
popupOnConfigChange = true;
showSummaryBeforeSync = true;
}
@@ -747,6 +748,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
inOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
inOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
+ inOpt["CheckMissingRecycleBin"](config.optDialogs.warningRecyclerMissing);
inOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
inOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
@@ -761,6 +763,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inWnd["PosY" ](config.gui.dlgPos.y);
inWnd["Maximized"](config.gui.isMaximized);
+ inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
+
inWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
inWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
inWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
@@ -796,10 +800,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inGui["ExternalApplications"](config.gui.externelApplications);
//load config file history
- XmlIn inHist = inGui["ConfigHistory"];
-
- inHist.attribute("LastUsed", config.gui.lastUsedConfigFile);
- inHist(config.gui.cfgFileHistory);
+ inGui["LastConfigActive"](config.gui.lastUsedConfigFiles);
+ inGui["ConfigHistory"](config.gui.cfgFileHistory);
//last update check
inGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
@@ -812,7 +814,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
template <class ConfigType>
void readConfig(const wxString& filename, XmlType type, ConfigType& config)
{
- if (!fileExists(wxToZ(filename)))
+ if (!fileExists(toZ(filename)))
throw FfsXmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
XmlDoc doc;
@@ -1003,6 +1005,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
outOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
outOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
+ outOpt["CheckMissingRecycleBin"](config.optDialogs.warningRecyclerMissing);
outOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
outOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
@@ -1017,6 +1020,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outWnd["PosY" ](config.gui.dlgPos.y);
outWnd["Maximized"](config.gui.isMaximized);
+ outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
+
outWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
outWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
outWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
@@ -1048,10 +1053,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outGui["ExternalApplications"](config.gui.externelApplications);
//load config file history
- XmlOut outHist = outGui["ConfigHistory"];
-
- outHist.attribute("LastUsed", config.gui.lastUsedConfigFile);
- outHist(config.gui.cfgFileHistory);
+ outGui["LastConfigActive"](config.gui.lastUsedConfigFiles);
+ outGui["ConfigHistory"](config.gui.cfgFileHistory);
//last update check
outGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
diff --git a/library/process_xml.h b/library/process_xml.h
index 2e57c433..d7437825 100644
--- a/library/process_xml.h
+++ b/library/process_xml.h
@@ -125,6 +125,7 @@ struct OptionalDialogs
bool warningNotEnoughDiskSpace;
bool warningUnresolvedConflicts;
bool warningSyncDatabase;
+ bool warningRecyclerMissing;
bool popupOnConfigChange;
bool showSummaryBeforeSync;
};
@@ -159,6 +160,7 @@ struct XmlGlobalSettings
dlgPos(wxDefaultCoord, wxDefaultCoord),
dlgSize(wxDefaultCoord, wxDefaultCoord),
isMaximized(false),
+ maxFolderPairsVisible(6),
autoAdjustColumnsLeft(false),
autoAdjustColumnsRight(false),
folderHistMax(12),
@@ -191,6 +193,8 @@ struct XmlGlobalSettings
wxSize dlgSize;
bool isMaximized;
+ int maxFolderPairsVisible;
+
ColumnAttributes columnAttribLeft;
ColumnAttributes columnAttribRight;
@@ -200,7 +204,7 @@ struct XmlGlobalSettings
ExternalApps externelApplications;
std::vector<wxString> cfgFileHistory;
- wxString lastUsedConfigFile;
+ std::vector<wxString> lastUsedConfigFiles;
std::vector<wxString> folderHistoryLeft;
std::vector<wxString> folderHistoryRight;
diff --git a/library/resources.cpp b/library/resources.cpp
index abdfdf51..179033a7 100644
--- a/library/resources.cpp
+++ b/library/resources.cpp
@@ -11,7 +11,6 @@
#include <wx/icon.h>
#include <wx/mstream.h>
#include "../shared/string_conv.h"
-#include "../shared/system_constants.h"
#include <memory>
#include "../shared/standard_paths.h"
@@ -102,9 +101,6 @@ void GlobalResources::load()
//for compatibility it seems we need to stick with a "real" icon
*programIcon = wxIcon(wxT("A_PROGRAM_ICON"));
#else
- //#include "FreeFileSync.xpm"
- //*programIcon = wxIcon(FreeFileSync_xpm);
-
//use big logo bitmap for better quality
programIcon->CopyFromBitmap(getImage(wxT("FreeFileSync.png")));
#endif
diff --git a/library/soft_filter.h b/library/soft_filter.h
index 82ba0ba2..0a406907 100644
--- a/library/soft_filter.h
+++ b/library/soft_filter.h
@@ -28,22 +28,25 @@ public:
size_t sizeMin, UnitSize unitSizeMin,
size_t sizeMax, UnitSize unitSizeMax);
- bool matchTime(zen::Int64 writeTime) const { return currentTime - writeTime <= timeSpan_; }
- bool matchSize(zen::UInt64 fileSize) const { return sizeMin_ <= fileSize && fileSize <= sizeMax_; }
+ bool matchTime(Int64 writeTime) const { return currentTime - writeTime <= timeSpan_; }
+ bool matchSize(UInt64 fileSize) const { return sizeMin_ <= fileSize && fileSize <= sizeMax_; }
+ bool matchFolder() const { return timeSpan_ == std::numeric_limits<Int64>::max(); }
+ //if date filter is active we deactivate all folders: effectively gets rid of empty folders!
+
bool isNull() const; //filter is equivalent to NullFilter, but may be technically slower
//small helper method: merge two soft filters
friend SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second);
private:
- 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(Int64 timeSpan,
+ UInt64 sizeMin,
+ UInt64 sizeMax);
+
+ Int64 timeSpan_; //unit: seconds
+ UInt64 sizeMin_; //unit: bytes
+ UInt64 sizeMax_; //unit: bytes
+ Int64 currentTime;
};
}
@@ -84,18 +87,18 @@ SoftFilter::SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
size_t sizeMax, UnitSize unitSizeMax) :
currentTime(wxGetUTCTime())
{
- zen::resolveUnits(timeSpan, unitTimeSpan,
- sizeMin, unitSizeMin,
- sizeMax, unitSizeMax,
- timeSpan_, //unit: seconds
- sizeMin_, //unit: bytes
- sizeMax_); //unit: bytes
+ 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) :
+SoftFilter::SoftFilter(Int64 timeSpan,
+ UInt64 sizeMin,
+ UInt64 sizeMax) :
timeSpan_(timeSpan),
sizeMin_ (sizeMin),
sizeMax_ (sizeMax),
@@ -112,9 +115,9 @@ SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second)
inline
bool SoftFilter::isNull() const //filter is equivalent to NullFilter, but may be technically slower
{
- return timeSpan_ == std::numeric_limits<zen::Int64>::max() &&
+ return timeSpan_ == std::numeric_limits<Int64>::max() &&
sizeMin_ == 0U &&
- sizeMax_ == std::numeric_limits<zen::UInt64>::max();
+ sizeMax_ == std::numeric_limits<UInt64>::max();
}
}
diff --git a/library/statistics.cpp b/library/statistics.cpp
index c2ba8c0c..812c869b 100644
--- a/library/statistics.cpp
+++ b/library/statistics.cpp
@@ -136,7 +136,6 @@ wxString Statistics::formatRemainingTime(double timeInMs) const
}
output.Replace(wxT("%x"), zen::toStringSep(formattedTime));
return output;
- //+ wxT("(") + common::numberToWxString(common::round(timeInMs / 1000)) + wxT(")");
}
@@ -227,7 +226,8 @@ wxString Statistics::getBytesPerSecond() const
const double dataDelta = backRecord.second.data - frontRecord.second.data;
if (!isNull(timeDelta))
- return zen::formatFilesizeToShortString(zen::UInt64(dataDelta * 1000 / timeDelta)) + _("/sec");
+ if (dataDelta > 0) //may be negative if user cancels copying
+ return zen::formatFilesizeToShortString(zen::UInt64(dataDelta * 1000 / timeDelta)) + _("/sec");
}
return wxT("-"); //fallback
diff --git a/library/status_handler.h b/library/status_handler.h
index c3a016d5..a7984790 100644
--- a/library/status_handler.h
+++ b/library/status_handler.h
@@ -8,7 +8,7 @@
#define STATUSHANDLER_H_INCLUDED
#include <wx/string.h>
-#include "../shared/zstring.h"
+#include <string>
#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
@@ -18,21 +18,6 @@ void updateUiNow(); //do the updating
//interfaces for status updates (can be implemented by GUI or Batch mode)
-//overwrite virtual methods for respective functionality
-
-class ErrorHandler
-{
-public:
- ErrorHandler() {}
- virtual ~ErrorHandler() {}
-
- enum Response
- {
- IGNORE_ERROR = 10,
- RETRY
- };
- virtual Response reportError(const Zstring& errorMessage) = 0;
-};
//report status during comparison and synchronization
@@ -51,21 +36,29 @@ struct ProcessCallback
//these methods have to be implemented in the derived classes to handle error and status information
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;
+ //called periodically after data was processed: expected(!) to update GUI!
+ virtual void reportInfo(const wxString& text) = 0;
- //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
- virtual void forceUiRefresh() = 0;
+ //note: this one must NOT throw in order to properly allow undoing setting of statistics!
+ //it is in general paired with a call to requestUiRefresh() to compensate!
+ virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw()
- virtual void requestUiRefresh(bool allowExceptions = true) = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
+ //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
+ virtual void requestUiRefresh() = 0; //throw ?
- virtual bool abortIsRequested() = 0; //thanks to Windows C-Api not supporting exceptions we need this one...
+ //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
+ virtual void forceUiRefresh() = 0;
//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;
+ enum Response
+ {
+ IGNORE_ERROR = 10,
+ RETRY
+ };
+ virtual 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;
};
@@ -83,18 +76,18 @@ class StatusHandler : public ProcessCallback, public AbortCallback
public:
StatusHandler() : abortRequested(false) {}
- virtual void requestUiRefresh(bool allowExceptions)
+ virtual void requestUiRefresh()
{
if (updateUiIsAllowed()) //test if specific time span between ui updates is over
forceUiRefresh();
- if (abortRequested && allowExceptions)
+ if (abortRequested)
abortThisProcess(); //abort can be triggered by requestAbortion()
}
- 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;
+ virtual void requestAbortion() { abortRequested = true; } //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished)
+ bool abortIsRequested() { return abortRequested; }
private:
bool abortRequested;
bgstack15