diff options
45 files changed, 641 insertions, 601 deletions
diff --git a/Changelog.txt b/Changelog.txt index 3ff45e86..897f7a5d 100755 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,23 @@ -FreeFileSync 9.3 ----------------- +FreeFileSync 9.4 [2017-10-05] +----------------------------- +Fixed copying files with locked byte ranges using VSS +Fixed wrong FTP working directory reuse in libcurl +Allow retry upon failure during online update check +Repackaged Donation Edition to reduce AV false positives (Norton) +Apply correct directory path encoding during FTP traversal +Fixed strict weak ordering for SFTP session ID sorting +Clean up read-only temporary files during failed sparse file copy +Fixed access denied file copy error for ADS while using BackupWrite +Workaround broken non-Windows SMB implementations reporting sparse support +Support hash characters in FTP directory listing +Prepared auto-updater to support new installer format +Refined installer error reporting +Streamlined sync config dialogs +Resized installer window dimensions + + +FreeFileSync 9.3 [2017-08-09] +----------------------------- Support multiple connections per FTP folder traversal: N times speed up Improved folder traversal time by 35% for FTP servers supporting MLSD Use single CWD when changing FTP working directory diff --git a/FreeFileSync/Build/Help/html/exclude-items.html b/FreeFileSync/Build/Help/html/exclude-items.html index a30dcaf7..563d4271 100755 --- a/FreeFileSync/Build/Help/html/exclude-items.html +++ b/FreeFileSync/Build/Help/html/exclude-items.html @@ -56,7 +56,7 @@ <td><span class="file-path">*temp*</span></td> </tr> <tr> - <td>Multiple entries separated by semicolon</td> + <td>Multiple entries separated by vertical bar</td> <td><span class="file-path">*.tmp | *.doc | *.bak</span></td> </tr> <tr> diff --git a/FreeFileSync/Build/Help/html/synchronize-with-sftp.html b/FreeFileSync/Build/Help/html/synchronize-with-sftp.html index ac43a186..50b119b2 100755 --- a/FreeFileSync/Build/Help/html/synchronize-with-sftp.html +++ b/FreeFileSync/Build/Help/html/synchronize-with-sftp.html @@ -30,8 +30,10 @@ Since most of this time is spent waiting due to the high latency of the remote connection, you can speed up reading large directory hierarchies by increasing both the connection and channel count.<br> <br> - <em>The directory reading time is reduced by a factor of N x M when using N connections with M channels each.</em><br> - <br> + <em>The directory reading time is reduced by a factor of <b>N</b> x <b>M</b> when using N connections with M channels each.</em> + <br><br> + <b>Example</b>: 2 connections using 10 channels each can yield a <b>20</b> times faster directory reading. + <br><br> <img src="../images/sftp-performance.png" alt="Set up SFTP for best performance"> <ul style="margin: 0"> diff --git a/FreeFileSync/Build/Help/images/sftp-login.png b/FreeFileSync/Build/Help/images/sftp-login.png Binary files differindex ebe1273e..1e5f05ca 100755 --- a/FreeFileSync/Build/Help/images/sftp-login.png +++ b/FreeFileSync/Build/Help/images/sftp-login.png diff --git a/FreeFileSync/Build/Help/images/sftp-performance.png b/FreeFileSync/Build/Help/images/sftp-performance.png Binary files differindex af1f7a4f..309e373e 100755 --- a/FreeFileSync/Build/Help/images/sftp-performance.png +++ b/FreeFileSync/Build/Help/images/sftp-performance.png diff --git a/FreeFileSync/Build/Languages/english_uk.lng b/FreeFileSync/Build/Languages/english_uk.lng index ccacb1f7..14ab1a32 100755 --- a/FreeFileSync/Build/Languages/english_uk.lng +++ b/FreeFileSync/Build/Languages/english_uk.lng @@ -7,6 +7,27 @@ <plural_definition>n == 1 ? 0 : 1</plural_definition> </header> +<source>Please enter a file path.</source> +<target></target> + +<source>Support with a donation</source> +<target></target> + +<source>4 connections = 4 times faster directory reading</source> +<target></target> + +<source>Connections for directory reading:</source> +<target></target> + +<source>&SSH agent</source> +<target></target> + +<source>Ignore &all</source> +<target></target> + +<source>The %x protocol does not support directory monitoring:</source> +<target></target> + <source>Both sides have changed since last synchronization.</source> <target>Both sides have changed since last synchronisation.</target> @@ -88,17 +109,14 @@ <source>Syntax:</source> <target>Syntax:</target> -<source>global config file:</source> -<target>global config file:</target> - <source>config files:</source> <target>config files:</target> <source>directory</source> <target>directory</target> -<source>Path to an alternate GlobalSettings.xml file.</source> -<target>Path to an alternate GlobalSettings.xml file.</target> +<source>global config file:</source> +<target>global config file:</target> <source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source> <target>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</target> @@ -109,6 +127,9 @@ <source>Open configuration for editing without executing it.</source> <target>Open configuration for editing without executing it.</target> +<source>Path to an alternate GlobalSettings.xml file.</source> +<target>Path to an alternate GlobalSettings.xml file.</target> + <source>Cannot find the following folders:</source> <target>Cannot find the following folders:</target> @@ -253,8 +274,8 @@ <source>Update attributes on right</source> <target>Update attributes on right</target> -<source>Cannot write file %x.</source> -<target>Cannot write file %x.</target> +<source>Cannot read file %x.</source> +<target>Cannot read file %x.</target> <source> Unexpected size of data stream. @@ -273,12 +294,15 @@ Actual: %y bytes <source>Operation not supported for different base folder types.</source> <target>Operation not supported for different base folder types.</target> -<source>Cannot copy symbolic link %x to %y.</source> -<target>Cannot copy symbolic link %x to %y.</target> +<source>Cannot write file %x.</source> +<target>Cannot write file %x.</target> <source>Cannot move file %x to %y.</source> <target>Cannot move file %x to %y.</target> +<source>Cannot copy symbolic link %x to %y.</source> +<target>Cannot copy symbolic link %x to %y.</target> + <source>Unable to connect to %x.</source> <target>Unable to connect to %x.</target> @@ -291,8 +315,8 @@ Actual: %y bytes <source>Cannot read directory %x.</source> <target>Cannot read directory %x.</target> -<source>Cannot read file %x.</source> -<target>Cannot read file %x.</target> +<source>Cannot read file attributes of %x.</source> +<target>Cannot read file attributes of %x.</target> <source>Cannot create directory %x.</source> <target>Cannot create directory %x.</target> @@ -303,9 +327,6 @@ Actual: %y bytes <source>Cannot delete directory %x.</source> <target>Cannot delete directory %x.</target> -<source>Cannot read file attributes of %x.</source> -<target>Cannot read file attributes of %x.</target> - <source>Cannot write modification time of %x.</source> <target>Cannot write modification time of %x.</target> @@ -596,9 +617,6 @@ The command is triggered if: <source>Automated Synchronization</source> <target>Automated Synchronisation</target> -<source>The following path does not support directory monitoring:</source> -<target>The following path does not support directory monitoring:</target> - <source>Directory monitoring active</source> <target>Directory monitoring active</target> @@ -776,9 +794,6 @@ The command is triggered if: <pluralform>Automatic retry in %x seconds...</pluralform> </target> -<source>&Ignore subsequent errors</source> -<target>&Ignore subsequent errors</target> - <source>Retrying operation...</source> <target>Retrying operation...</target> @@ -884,12 +899,12 @@ The command is triggered if: <source>&Find...</source> <target>&Find...</target> -<source>&Reset layout</source> -<target>&Reset layout</target> - <source>&Export file list...</source> <target>&Export file list...</target> +<source>&Reset layout</source> +<target>&Reset layout</target> + <source>&Tools</source> <target>&Tools</target> @@ -1135,9 +1150,6 @@ The command is triggered if: <source>How to get best performance?</source> <target>How to get best performance?</target> -<source>SSH connections for directory reading:</source> -<target>SSH connections for directory reading:</target> - <source>Suggested range: [1 - 10]</source> <target>Suggested range: [1 - 10]</target> @@ -1279,14 +1291,11 @@ This guarantees a consistent state even in case of a serious error. <source>Source code written in C++ using:</source> <target>Source code written in C++ using:</target> -<source>Donation details</source> -<target>Donation details</target> - <source>If you like FreeFileSync:</source> <target>If you like FreeFileSync:</target> -<source>Donate with PayPal</source> -<target>Donate with PayPal</target> +<source>Donation details</source> +<target>Donation details</target> <source>Feedback and suggestions are welcome</source> <target>Feedback and suggestions are welcome</target> @@ -1363,6 +1372,9 @@ This guarantees a consistent state even in case of a serious error. <source>Overview</source> <target>Overview</target> +<source>Show "%x"</source> +<target>Show "%x"</target> + <source>&Show details</source> <target>&Show details</target> @@ -1459,9 +1471,6 @@ This guarantees a consistent state even in case of a serious error. <source>Select time span...</source> <target>Select time span...</target> -<source>Show "%x"</source> -<target>Show "%x"</target> - <source>Last session</source> <target>Last session</target> diff --git a/FreeFileSync/Build/Languages/german.lng b/FreeFileSync/Build/Languages/german.lng index ef2a8463..f404476d 100755 --- a/FreeFileSync/Build/Languages/german.lng +++ b/FreeFileSync/Build/Languages/german.lng @@ -7,6 +7,9 @@ <plural_definition>n == 1 ? 0 : 1</plural_definition> </header> +<source>Support with a donation</source> +<target>Mit einer Spende unterstützen</target> + <source>Both sides have changed since last synchronization.</source> <target>Beide Seiten wurden seit der letzten Synchronisation verändert.</target> @@ -1291,9 +1294,6 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert. <source>If you like FreeFileSync:</source> <target>Wenn Sie FreeFileSync mögen:</target> -<source>Donate with PayPal</source> -<target>Mit PayPal spenden</target> - <source>Feedback and suggestions are welcome</source> <target>Feedback und Vorschläge sind willkommen</target> diff --git a/FreeFileSync/Build/Resources.zip b/FreeFileSync/Build/Resources.zip Binary files differindex 3cf35133..18d7907c 100755 --- a/FreeFileSync/Build/Resources.zip +++ b/FreeFileSync/Build/Resources.zip diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp index cf3d28d2..a54a93f1 100755 --- a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp +++ b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp @@ -13,6 +13,7 @@ #include <wx+/image_resources.h> #include <zen/file_access.h> #include <zen/build_info.h> +#include <zen/time.h> #include "xml_proc.h" #include "tray_menu.h" #include "app_icon.h" @@ -157,7 +158,7 @@ void MainDialog::OnShowHelp(wxCommandEvent& event) void MainDialog::OnMenuAbout(wxCommandEvent& event) { - wxString build = __TDATE__; + wxString build = formatTime<std::wstring>(FORMAT_DATE, getCompileTime()); build += L" - Unicode"; #ifndef wxUSE_UNICODE #error what is going on? diff --git a/FreeFileSync/Source/algorithm.cpp b/FreeFileSync/Source/algorithm.cpp index b519da44..90f60a6a 100755 --- a/FreeFileSync/Source/algorithm.cpp +++ b/FreeFileSync/Source/algorithm.cpp @@ -1576,7 +1576,7 @@ void zen::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDelete if (useRecycleBin && std::any_of(recyclerSupported.begin(), recyclerSupported.end(), [](const auto& item) { return !item.second; })) { - std::wstring msg = _("The recycle bin is not available for the following folders. Files will be deleted permanently instead:") + L"\n"; + std::wstring msg = _("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L"\n"; for (const auto& item : recyclerSupported) if (!item.second) diff --git a/FreeFileSync/Source/application.cpp b/FreeFileSync/Source/application.cpp index a86016a2..6ed0426c 100755 --- a/FreeFileSync/Source/application.cpp +++ b/FreeFileSync/Source/application.cpp @@ -420,7 +420,7 @@ void showSyntaxHelp() _("Any number of alternative directory pairs for at most one config file.") + L"\n\n" + L"-Edit" + L"\n" + - _("Open configuration for editing without executing it.") + L"\n\n" + + _("Open the selected configuration for editing only without executing it.") + L"\n\n" + _("global config file:") + L"\n" + _("Path to an alternate GlobalSettings.xml file."))); diff --git a/FreeFileSync/Source/file_hierarchy.cpp b/FreeFileSync/Source/file_hierarchy.cpp index 19843669..4d0330a3 100755 --- a/FreeFileSync/Source/file_hierarchy.cpp +++ b/FreeFileSync/Source/file_hierarchy.cpp @@ -46,10 +46,10 @@ SyncOperation getIsolatedSyncOperation(bool itemExistsLeft, SyncDirection syncDir, bool hasDirectionConflict) //perf: std::wstring was wasteful here { - assert(( itemExistsLeft && itemExistsRight && cmpResult != FILE_LEFT_SIDE_ONLY && cmpResult != FILE_RIGHT_SIDE_ONLY) || - ( itemExistsLeft && !itemExistsRight && cmpResult == FILE_LEFT_SIDE_ONLY ) || - (!itemExistsLeft && itemExistsRight && cmpResult == FILE_RIGHT_SIDE_ONLY) || - (!itemExistsLeft && !itemExistsRight && cmpResult == FILE_EQUAL && syncDir == SyncDirection::NONE && !hasDirectionConflict) || + assert(( itemExistsLeft && itemExistsRight && cmpResult != FILE_LEFT_SIDE_ONLY && cmpResult != FILE_RIGHT_SIDE_ONLY) || + ( itemExistsLeft && !itemExistsRight && cmpResult == FILE_LEFT_SIDE_ONLY ) || + (!itemExistsLeft && itemExistsRight && cmpResult == FILE_RIGHT_SIDE_ONLY) || + (!itemExistsLeft && !itemExistsRight && cmpResult == FILE_EQUAL && syncDir == SyncDirection::NONE && !hasDirectionConflict) || cmpResult == FILE_CONFLICT); assert(!hasDirectionConflict || syncDir == SyncDirection::NONE); diff --git a/FreeFileSync/Source/file_hierarchy.h b/FreeFileSync/Source/file_hierarchy.h index 4d12259d..59a76fcd 100755 --- a/FreeFileSync/Source/file_hierarchy.h +++ b/FreeFileSync/Source/file_hierarchy.h @@ -345,11 +345,24 @@ public: inline friend bool operator==(const DerefIter& lhs, const DerefIter& rhs) { return lhs.it_ == rhs.it_; } inline friend bool operator!=(const DerefIter& lhs, const DerefIter& rhs) { return !(lhs == rhs); } V& operator* () const { return **it_; } - V* operator->() const { return &** it_; } + V* operator->() const { return &**it_; } private: IterImpl it_; }; +/* +C++17: specialize std::iterator_traits instead of inherting from std::iterator +namespace std +{ +template <class IterImpl, class V> +struct iterator_traits<zen::DerefIter<IterImpl, V>> +{ + using iterator_category = std::bidirectional_iterator_tag; + using value_type = V; +}; +} +*/ + using FolderComparison = std::vector<std::shared_ptr<BaseFolderPair>>; //make sure pointers to sub-elements remain valid //don't change this back to std::vector<BaseFolderPair> too easily: comparison uses push_back to add entries which may result in a full copy! diff --git a/FreeFileSync/Source/fs/abstract.cpp b/FreeFileSync/Source/fs/abstract.cpp index 5f2613ee..e23c5abf 100755 --- a/FreeFileSync/Source/fs/abstract.cpp +++ b/FreeFileSync/Source/fs/abstract.cpp @@ -86,7 +86,7 @@ AFS::FileCopyResult AFS::copyFileAsStream(const AfsPath& afsPathSource, const St //target existing: undefined behavior! (fail/overwrite/auto-rename) auto streamOut = getOutputStream(apTarget, &attrSourceNew.fileSize, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //throw FileError - bufferedStreamCopy(*streamIn, *streamOut); //throw FileError, X + bufferedStreamCopy(*streamIn, *streamOut); //throw FileError, ErrorFileLocked, X const FileId targetFileId = streamOut->finalize(); //throw FileError, X diff --git a/FreeFileSync/Source/fs/abstract.h b/FreeFileSync/Source/fs/abstract.h index a343fbe9..6fb561b4 100755 --- a/FreeFileSync/Source/fs/abstract.h +++ b/FreeFileSync/Source/fs/abstract.h @@ -138,7 +138,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t struct InputStream { virtual ~InputStream() {} - virtual size_t read(void* buffer, size_t bytesToRead) = 0; //throw FileError, X; return "bytesToRead" bytes unless end of stream! + virtual size_t read(void* buffer, size_t bytesToRead) = 0; //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream! virtual size_t getBlockSize() const = 0; //non-zero block size is AFS contract! it's implementer's job to always give a reasonable buffer size! //only returns attributes if they are already buffered within stream handle and determination would be otherwise expensive (e.g. FTP/SFTP): diff --git a/FreeFileSync/Source/fs/native.cpp b/FreeFileSync/Source/fs/native.cpp index dfec9180..cd3e5002 100755 --- a/FreeFileSync/Source/fs/native.cpp +++ b/FreeFileSync/Source/fs/native.cpp @@ -62,7 +62,7 @@ struct InputStreamNative : public AbstractFileSystem::InputStream { InputStreamNative(const Zstring& filePath, const IOCallback& notifyUnbufferedIO) : fi_(filePath, notifyUnbufferedIO) {} //throw FileError, ErrorFileLocked - size_t read(void* buffer, size_t bytesToRead) override { return fi_.read(buffer, bytesToRead); } //throw FileError, X; return "bytesToRead" bytes unless end of stream! + size_t read(void* buffer, size_t bytesToRead) override { return fi_.read(buffer, bytesToRead); } //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream! size_t getBlockSize() const override { return fi_.getBlockSize(); } //non-zero block size is AFS contract! Opt<AFS::StreamAttributes> getAttributesBuffered() override; //throw FileError diff --git a/FreeFileSync/Source/lib/binary.cpp b/FreeFileSync/Source/lib/binary.cpp index 0b7d8905..da68f573 100755 --- a/FreeFileSync/Source/lib/binary.cpp +++ b/FreeFileSync/Source/lib/binary.cpp @@ -37,8 +37,8 @@ const size_t BLOCK_SIZE_MAX = 16 * 1024 * 1024; struct StreamReader { - StreamReader(const AbstractPath& filePath, const IOCallback& notifyUnbufferedIO) : - stream_(AFS::getInputStream(filePath, notifyUnbufferedIO)), //throw FileError, (ErrorFileLocked), X + StreamReader(const AbstractPath& filePath, const IOCallback& notifyUnbufferedIO) : //throw FileError, X + stream_(AFS::getInputStream(filePath, notifyUnbufferedIO)), //throw FileError, ErrorFileLocked, X defaultBlockSize_(stream_->getBlockSize()), dynamicBlockSize_(defaultBlockSize_) { assert(defaultBlockSize_ > 0); } @@ -50,7 +50,7 @@ struct StreamReader buffer.resize(buffer.size() + dynamicBlockSize_); const auto startTime = std::chrono::steady_clock::now(); - const size_t bytesRead = stream_->read(&*(buffer.end() - dynamicBlockSize_), dynamicBlockSize_); //throw FileError, X; return "bytesToRead" bytes unless end of stream! + const size_t bytesRead = stream_->read(&*(buffer.end() - dynamicBlockSize_), dynamicBlockSize_); //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream! const auto stopTime = std::chrono::steady_clock::now(); buffer.resize(buffer.size() - dynamicBlockSize_ + bytesRead); //caveat: unsigned arithmetics @@ -96,7 +96,7 @@ bool zen::filesHaveSameContent(const AbstractPath& filePath1, const AbstractPath { int64_t totalUnbufferedIO = 0; - StreamReader reader1(filePath1, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //throw FileError, (ErrorFileLocked), X + StreamReader reader1(filePath1, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //throw FileError, X StreamReader reader2(filePath2, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); // StreamReader* readerLow = &reader1; diff --git a/FreeFileSync/Source/lib/db_file.cpp b/FreeFileSync/Source/lib/db_file.cpp index 796efb87..a41690bc 100755 --- a/FreeFileSync/Source/lib/db_file.cpp +++ b/FreeFileSync/Source/lib/db_file.cpp @@ -94,12 +94,12 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff //read FreeFileSync file identifier char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {}; - readArray(*fileStreamIn, formatDescr, sizeof(formatDescr)); //throw FileError, X, UnexpectedEndOfStreamError + readArray(*fileStreamIn, formatDescr, sizeof(formatDescr)); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr)) throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtPath(AFS::getDisplayPath(dbPath)))); - const int version = readNumber<int32_t>(*fileStreamIn); //throw FileError, X, UnexpectedEndOfStreamError + const int version = readNumber<int32_t>(*fileStreamIn); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError //TODO: remove migration code at some time! 2017-02-01 if (version != 9 && @@ -109,18 +109,18 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff DbStreams output; //read stream list - size_t dbCount = readNumber<uint32_t>(*fileStreamIn); //throw FileError, X, UnexpectedEndOfStreamError + size_t dbCount = readNumber<uint32_t>(*fileStreamIn); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError while (dbCount-- != 0) { //DB id of partner databases - std::string sessionID = readContainer<std::string>(*fileStreamIn); //throw FileError, X, UnexpectedEndOfStreamError + std::string sessionID = readContainer<std::string>(*fileStreamIn); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError SessionData sessionData = {}; //TODO: remove migration code at some time! 2017-02-01 if (version == 9) { - sessionData.rawStream = readContainer<ByteArray>(*fileStreamIn); //throw FileError, X, UnexpectedEndOfStreamError + sessionData.rawStream = readContainer<ByteArray>(*fileStreamIn); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError MemoryStreamIn<ByteArray> streamIn(sessionData.rawStream); const int streamVersion = readNumber<int32_t>(streamIn); //throw UnexpectedEndOfStreamError @@ -130,8 +130,8 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff } else { - sessionData.isLeadStream = readNumber<int8_t>(*fileStreamIn) != 0; //throw FileError, X, UnexpectedEndOfStreamError - sessionData.rawStream = readContainer<ByteArray>(*fileStreamIn); //throw FileError, X, UnexpectedEndOfStreamError + sessionData.isLeadStream = readNumber<int8_t>(*fileStreamIn) != 0; //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError + sessionData.rawStream = readContainer<ByteArray>(*fileStreamIn); //throw FileError, ErrorFileLocked, X, UnexpectedEndOfStreamError } output[sessionID] = std::move(sessionData); @@ -558,37 +558,13 @@ private: } template <class M, class V> - static V& updateItem(M& map, const Zstring& key, const V& value) + static V& mapAddOrUpdate(M& map, const Zstring& key, V&& value) { - auto rv = map.emplace(key, value); - if (!rv.second) - { - rv.first->second = value; - } - return rv.first->second; - - //www.cplusplus.com claims that hint position for map<>::insert(iterator position, const value_type& val) changed with C++11 -> standard is unclear in [map.modifiers] - // => let's use the more generic and potentially less performant version above! - - /* - //efficient create or update without "default-constructible" requirement (Effective STL, item 24) + auto rv = map.emplace(key, value); //C++11 emplace will move r-value arguments => don't use std::forward! + if (rv.second) + return rv.first->second; - //first check if key already exists (if yes, we're saving a value construction/destruction compared to std::map<>::insert - auto it = map.lower_bound(key); - if (it != map.end() && !(map.key_comp()(key, it->first))) - { - #if defined ZEN_WIN || defined ZEN_MAC //caveat: key might need to be updated, too, if there is a change in short name case!!! - if (it->first != key) - { - map.erase(it); //don't fiddle with decrementing "it"! - you might lose while optimizing pointlessly - return map.emplace(key, value).first->second; - } - #endif - it->second = value; - return it->second; - } - return map.insert(it, typename M::value_type(key, value))->second; - */ + return rv.first->second = std::forward<V>(value); } void process(const ContainerObject::FileList& currentFiles, const Zstring& parentRelPath, InSyncFolder::FileList& dbFiles) @@ -607,7 +583,7 @@ private: assert(file.getFileSize<LEFT_SIDE>() == file.getFileSize<RIGHT_SIDE>()); //create or update new "in-sync" state - InSyncFile& dbFile = updateItem(dbFiles, file.getPairItemName(), + InSyncFile& dbFile = mapAddOrUpdate(dbFiles, file.getPairItemName(), InSyncFile(InSyncDescrFile(file.getLastWriteTime< LEFT_SIDE>(), file.getFileId < LEFT_SIDE>()), InSyncDescrFile(file.getLastWriteTime<RIGHT_SIDE>(), @@ -648,7 +624,7 @@ private: assert(symlink.getItemName<LEFT_SIDE>() == symlink.getItemName<RIGHT_SIDE>()); //create or update new "in-sync" state - InSyncSymlink& dbSymlink = updateItem(dbSymlinks, symlink.getPairItemName(), + InSyncSymlink& dbSymlink = mapAddOrUpdate(dbSymlinks, symlink.getPairItemName(), InSyncSymlink(InSyncDescrLink(symlink.getLastWriteTime<LEFT_SIDE>()), InSyncDescrLink(symlink.getLastWriteTime<RIGHT_SIDE>()), activeCmpVar_)); diff --git a/FreeFileSync/Source/lib/parallel_scan.cpp b/FreeFileSync/Source/lib/parallel_scan.cpp index b9e80453..376a2e01 100755 --- a/FreeFileSync/Source/lib/parallel_scan.cpp +++ b/FreeFileSync/Source/lib/parallel_scan.cpp @@ -55,9 +55,9 @@ DiskInfo retrieveDiskInfo(const Zstring& itemPath) DiskInfo output; //full pathName need not yet exist! - if (!::GetVolumePathName(itemPath.c_str(), //__in LPCTSTR lpszFileName, - &volName[0], //__out LPTSTR lpszVolumePathName, - static_cast<DWORD>(volName.size()))) //__in DWORD cchBufferLength + if (!::GetVolumePathName(itemPath.c_str(), //__in LPCTSTR lpszFileName, + &volName[0], //__out LPTSTR lpszVolumePathName, + static_cast<DWORD>(volName.size()))) //__in DWORD cchBufferLength return output; const Zstring rootPathName = &volName[0]; diff --git a/FreeFileSync/Source/lib/resolve_path.cpp b/FreeFileSync/Source/lib/resolve_path.cpp index 1c67bd78..c4c45779 100755 --- a/FreeFileSync/Source/lib/resolve_path.cpp +++ b/FreeFileSync/Source/lib/resolve_path.cpp @@ -80,6 +80,8 @@ Zstring resolveRelativePath(const Zstring& relativePath) + + //returns value if resolved Opt<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-characters { diff --git a/FreeFileSync/Source/lib/versioning.cpp b/FreeFileSync/Source/lib/versioning.cpp index 2cda977f..3a96628a 100755 --- a/FreeFileSync/Source/lib/versioning.cpp +++ b/FreeFileSync/Source/lib/versioning.cpp @@ -2,7 +2,6 @@ #include <cstddef> //required by GCC 4.8.1 to find ptrdiff_t using namespace zen; -using AFS = AbstractFileSystem; namespace diff --git a/FreeFileSync/Source/structures.cpp b/FreeFileSync/Source/structures.cpp index 11dafb3e..fb8e2824 100755 --- a/FreeFileSync/Source/structures.cpp +++ b/FreeFileSync/Source/structures.cpp @@ -270,11 +270,11 @@ int daysSinceBeginOfWeek(int dayOfWeek) //0-6, 0=Monday, 6=Sunday assert(0 <= dayOfWeek && dayOfWeek <= 6); #ifdef ZEN_WIN DWORD firstDayOfWeek = 0; - if (::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale, - LOCALE_IFIRSTDAYOFWEEK | // first day of week specifier, 0-6, 0=Monday, 6=Sunday - LOCALE_RETURN_NUMBER, //__in LCTYPE LCType, - reinterpret_cast<LPTSTR>(&firstDayOfWeek), //__out LPTSTR lpLCData, - sizeof(firstDayOfWeek) / sizeof(TCHAR)) > 0) //__in int cchData + if (::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale, + LOCALE_IFIRSTDAYOFWEEK | // first day of week specifier, 0-6, 0=Monday, 6=Sunday + LOCALE_RETURN_NUMBER, //__in LCTYPE LCType, + reinterpret_cast<LPTSTR>(&firstDayOfWeek), //__out LPTSTR lpLCData, + sizeof(firstDayOfWeek) / sizeof(TCHAR)) > 0) //__in int cchData { assert(firstDayOfWeek <= 6); return (dayOfWeek + (7 - firstDayOfWeek)) % 7; diff --git a/FreeFileSync/Source/synchronization.cpp b/FreeFileSync/Source/synchronization.cpp index a22903e1..b756459a 100755 --- a/FreeFileSync/Source/synchronization.cpp +++ b/FreeFileSync/Source/synchronization.cpp @@ -2041,7 +2041,7 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime msg += L"\n" + AFS::getDisplayPath(item.first); if (!msg.empty()) - callback.reportWarning(_("The recycle bin is not available for the following folders. Files will be deleted permanently instead:") + L"\n" + msg, + callback.reportWarning(_("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L"\n" + msg, warnings.warnRecyclerMissing); } diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp index b6007636..c8244569 100755 --- a/FreeFileSync/Source/ui/gui_generated.cpp +++ b/FreeFileSync/Source/ui/gui_generated.cpp @@ -1126,38 +1126,27 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText91->Wrap( -1 ); bSizer182->Add( m_staticText91, 0, wxALL, 5 ); - wxFlexGridSizer* fgSizer16; - fgSizer16 = new wxFlexGridSizer( 3, 2, 5, 5 ); - fgSizer16->SetFlexibleDirection( wxBOTH ); - fgSizer16->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + wxBoxSizer* bSizer2381; + bSizer2381 = new wxBoxSizer( wxVERTICAL ); - m_bitmapByTimeSize = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer16->Add( m_bitmapByTimeSize, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_toggleBtnByTimeSize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File time and size"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_toggleBtnByTimeSize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File time and size"), wxDefaultPosition, wxSize( -1, 30 ), 0 ); m_toggleBtnByTimeSize->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - fgSizer16->Add( m_toggleBtnByTimeSize, 0, wxEXPAND, 5 ); - - m_bitmapByContent = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer16->Add( m_bitmapByContent, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer2381->Add( m_toggleBtnByTimeSize, 0, wxEXPAND|wxBOTTOM, 5 ); - m_toggleBtnByContent = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File content"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_toggleBtnByContent = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File content"), wxDefaultPosition, wxSize( -1, 30 ), 0 ); m_toggleBtnByContent->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - fgSizer16->Add( m_toggleBtnByContent, 0, wxEXPAND, 5 ); - - m_bitmapBySize = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer16->Add( m_bitmapBySize, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer2381->Add( m_toggleBtnByContent, 0, wxEXPAND|wxBOTTOM, 5 ); - m_toggleBtnBySize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File size"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_toggleBtnBySize = new wxToggleButton( m_panelComparisonSettings, wxID_ANY, _("File size"), wxDefaultPosition, wxSize( -1, 30 ), 0 ); m_toggleBtnBySize->SetValue( true ); m_toggleBtnBySize->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - fgSizer16->Add( m_toggleBtnBySize, 0, wxEXPAND, 5 ); + bSizer2381->Add( m_toggleBtnBySize, 0, wxEXPAND, 5 ); - bSizer182->Add( fgSizer16, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer182->Add( bSizer2381, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); bSizer178->Add( bSizer182, 0, wxALL, 5 ); @@ -1165,8 +1154,22 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticline42 = new wxStaticLine( m_panelComparisonSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); bSizer178->Add( m_staticline42, 0, wxEXPAND, 5 ); - m_textCtrlCompVarDescription = new wxTextCtrl( m_panelComparisonSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); - bSizer178->Add( m_textCtrlCompVarDescription, 1, wxEXPAND|wxLEFT, 5 ); + wxBoxSizer* bSizer2371; + bSizer2371 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapCompVariant = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_bitmapCompVariant->SetToolTip( _("Detect synchronization directions with the help of database files") ); + + bSizer2371->Add( m_bitmapCompVariant, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextCompVarDescription = new wxStaticText( m_panelComparisonSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCompVarDescription->Wrap( -1 ); + m_staticTextCompVarDescription->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + bSizer2371->Add( m_staticTextCompVarDescription, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer178->Add( bSizer2371, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); bSizer159->Add( bSizer178, 0, wxEXPAND, 5 ); @@ -1260,7 +1263,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_panelCompSettingsHolder->SetSizer( bSizer275 ); m_panelCompSettingsHolder->Layout(); bSizer275->Fit( m_panelCompSettingsHolder ); - m_notebook->AddPage( m_panelCompSettingsHolder, _("dummy"), true ); + m_notebook->AddPage( m_panelCompSettingsHolder, _("dummy"), false ); m_panelFilterSettingsHolder = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelFilterSettingsHolder->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); @@ -1532,7 +1535,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_toggleBtnTwoWay = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, 30 ), 0 ); m_toggleBtnTwoWay->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); - bSizer236->Add( m_toggleBtnTwoWay, 0, wxEXPAND|wxBOTTOM, 5 ); + bSizer236->Add( m_toggleBtnTwoWay, 0, wxBOTTOM|wxEXPAND, 5 ); m_toggleBtnMirror = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, 30 ), 0 ); m_toggleBtnMirror->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); @@ -1564,111 +1567,112 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer238->Add( 0, 0, 1, wxEXPAND, 5 ); - bSizerSyncConfig = new wxBoxSizer( wxHORIZONTAL ); - - wxBoxSizer* bSizer173; - bSizer173 = new wxBoxSizer( wxVERTICAL ); + bSizer233 = new wxBoxSizer( wxHORIZONTAL ); - - bSizer173->Add( 0, 0, 1, wxEXPAND, 5 ); + bSizerSyncDirections = new wxBoxSizer( wxVERTICAL ); m_staticText119 = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Category"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText119->Wrap( -1 ); - bSizer173->Add( m_staticText119, 0, 0, 5 ); + bSizerSyncDirections->Add( m_staticText119, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - - bSizer173->Add( 0, 0, 1, wxEXPAND, 5 ); - - - bSizer173->Add( 0, 0, 1, wxEXPAND, 5 ); - - m_staticText120 = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText120->Wrap( -1 ); - bSizer173->Add( m_staticText120, 0, 0, 5 ); - - - bSizer173->Add( 0, 0, 1, wxEXPAND, 5 ); - - - bSizerSyncConfig->Add( bSizer173, 0, wxEXPAND|wxRIGHT, 5 ); - - fgSizerSyncDirections = new wxFlexGridSizer( 2, 0, 5, 5 ); - fgSizerSyncDirections->SetFlexibleDirection( wxBOTH ); - fgSizerSyncDirections->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + ffgSizer11 = new wxFlexGridSizer( 2, 0, 5, 5 ); + ffgSizer11->SetFlexibleDirection( wxBOTH ); + ffgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_bitmapLeftOnly = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapLeftOnly->SetToolTip( _("Item exists on left side only") ); - fgSizerSyncDirections->Add( m_bitmapLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bitmapLeftNewer = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapLeftNewer->SetToolTip( _("Left side is newer") ); - fgSizerSyncDirections->Add( m_bitmapLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bitmapDifferent = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapDifferent->SetToolTip( _("Items have different content") ); - fgSizerSyncDirections->Add( m_bitmapDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bitmapConflict = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapConflict->SetToolTip( _("Conflict/item cannot be categorized") ); - fgSizerSyncDirections->Add( m_bitmapConflict, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapConflict, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bitmapRightNewer = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapRightNewer->SetToolTip( _("Right side is newer") ); - fgSizerSyncDirections->Add( m_bitmapRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bitmapRightOnly = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45, 45 ), 0 ); m_bitmapRightOnly->SetToolTip( _("Item exists on right side only") ); - fgSizerSyncDirections->Add( m_bitmapRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bitmapRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonLeftOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonLeftNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonDifferent = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonConflict = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonConflict, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonConflict, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonRightNewer = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonRightOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - fgSizerSyncDirections->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + ffgSizer11->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - bSizerSyncConfig->Add( fgSizerSyncDirections, 0, 0, 5 ); + bSizerSyncDirections->Add( ffgSizer11, 0, 0, 5 ); - m_bitmapDatabase = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); - m_bitmapDatabase->SetToolTip( _("Detect synchronization directions with the help of database files") ); + m_staticText120 = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText120->Wrap( -1 ); + bSizerSyncDirections->Add( m_staticText120, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 ); + + + bSizer233->Add( bSizerSyncDirections, 0, 0, 5 ); - bSizerSyncConfig->Add( m_bitmapDatabase, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxALIGN_CENTER_VERTICAL, 10 ); + wxBoxSizer* bSizerKeepVerticalHeight; + bSizerKeepVerticalHeight = new wxBoxSizer( wxVERTICAL ); - wxBoxSizer* bSizerKeepVerticalHeightWhenSyncDirsNotShown; - bSizerKeepVerticalHeightWhenSyncDirsNotShown = new wxBoxSizer( wxVERTICAL ); + m_staticText140 = new wxStaticText( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText140->Wrap( -1 ); + bSizerKeepVerticalHeight->Add( m_staticText140, 0, 0, 5 ); - bSizerKeepVerticalHeightWhenSyncDirsNotShown->Add( 0, 45, 0, 0, 5 ); + bSizerKeepVerticalHeight->Add( 0, 45, 0, 0, 5 ); - bSizerKeepVerticalHeightWhenSyncDirsNotShown->Add( 0, 5, 1, 0, 5 ); + bSizerKeepVerticalHeight->Add( 0, 5, 0, 0, 5 ); - bSizerKeepVerticalHeightWhenSyncDirsNotShown->Add( 0, 46, 0, 0, 5 ); + bSizerKeepVerticalHeight->Add( 0, 46, 0, 0, 5 ); + m_staticText1401 = new wxStaticText( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1401->Wrap( -1 ); + bSizerKeepVerticalHeight->Add( m_staticText1401, 0, wxTOP, 5 ); - bSizerSyncConfig->Add( bSizerKeepVerticalHeightWhenSyncDirsNotShown, 0, 0, 5 ); + bSizer233->Add( bSizerKeepVerticalHeight, 0, 0, 5 ); + + m_bitmapDatabase = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_bitmapDatabase->SetToolTip( _("Detect synchronization directions with the help of database files") ); - bSizer238->Add( bSizerSyncConfig, 0, wxALL, 10 ); + bSizer233->Add( m_bitmapDatabase, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxLEFT, 10 ); + + m_staticTextSyncVarDescription = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_staticTextSyncVarDescription->Wrap( -1 ); + m_staticTextSyncVarDescription->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + + bSizer233->Add( m_staticTextSyncVarDescription, 0, wxALL|wxALIGN_CENTER_VERTICAL, 10 ); + + + bSizer238->Add( bSizer233, 0, wxALL, 10 ); bSizer238->Add( 0, 0, 1, wxEXPAND, 5 ); @@ -1692,13 +1696,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer238->Add( bSizer201, 0, wxALL, 5 ); - bSizer237->Add( bSizer238, 0, wxEXPAND, 5 ); - - m_staticline531 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); - bSizer237->Add( m_staticline531, 0, wxEXPAND, 5 ); - - m_textCtrlSyncVarDescription = new wxTextCtrl( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER ); - bSizer237->Add( m_textCtrlSyncVarDescription, 1, wxLEFT|wxEXPAND, 5 ); + bSizer237->Add( bSizer238, 1, wxEXPAND, 5 ); bSizer232->Add( bSizer237, 0, wxEXPAND, 5 ); @@ -1706,7 +1704,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticline54 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizer232->Add( m_staticline54, 0, wxEXPAND, 5 ); - bSizerDelHandling = new wxBoxSizer( wxHORIZONTAL ); + bSizer2361 = new wxBoxSizer( wxHORIZONTAL ); wxBoxSizer* bSizer202; bSizer202 = new wxBoxSizer( wxVERTICAL ); @@ -1715,33 +1713,51 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText87->Wrap( -1 ); bSizer202->Add( m_staticText87, 0, wxALL, 5 ); - m_bpButtonDeletionType = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 46, 46 ), wxBU_AUTODRAW ); - bSizer202->Add( m_bpButtonDeletionType, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + wxBoxSizer* bSizer234; + bSizer234 = new wxBoxSizer( wxVERTICAL ); + + m_toggleBtnRecycler = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("&Recycle bin"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + m_toggleBtnRecycler->SetValue( true ); + bSizer234->Add( m_toggleBtnRecycler, 0, wxEXPAND, 5 ); + + m_toggleBtnPermanent = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("&Permanent"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + bSizer234->Add( m_toggleBtnPermanent, 0, wxEXPAND, 5 ); + + m_toggleBtnVersioning = new wxToggleButton( m_panelSyncSettings, wxID_ANY, _("&Versioning"), wxDefaultPosition, wxSize( -1, -1 ), 0 ); + bSizer234->Add( m_toggleBtnVersioning, 0, wxEXPAND, 5 ); - bSizerDelHandling->Add( bSizer202, 0, 0, 5 ); + bSizer202->Add( bSizer234, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - wxBoxSizer* bSizer2011; - bSizer2011 = new wxBoxSizer( wxVERTICAL ); - m_radioBtnRecycler = new wxRadioButton( m_panelSyncSettings, wxID_ANY, _("&Recycle bin"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); - m_radioBtnRecycler->SetValue( true ); - m_radioBtnRecycler->SetToolTip( _("Back up deleted and overwritten files in the recycle bin") ); + bSizer2361->Add( bSizer202, 0, wxALL, 5 ); - bSizer2011->Add( m_radioBtnRecycler, 0, wxEXPAND|wxALL, 5 ); + m_staticline531 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); + bSizer2361->Add( m_staticline531, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer2351; + bSizer2351 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer2331; + bSizer2331 = new wxBoxSizer( wxHORIZONTAL ); - m_radioBtnPermanent = new wxRadioButton( m_panelSyncSettings, wxID_ANY, _("&Permanent"), wxDefaultPosition, wxDefaultSize, 0 ); - m_radioBtnPermanent->SetToolTip( _("Delete or overwrite files permanently") ); + m_bitmapDeletionType = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2331->Add( m_bitmapDeletionType, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - bSizer2011->Add( m_radioBtnPermanent, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + m_staticTextDeletionTypeDescription = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDeletionTypeDescription->Wrap( -1 ); + m_staticTextDeletionTypeDescription->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - m_radioBtnVersioning = new wxRadioButton( m_panelSyncSettings, wxID_ANY, _("&Versioning"), wxDefaultPosition, wxDefaultSize, 0 ); - m_radioBtnVersioning->SetToolTip( _("Move files to a user-defined folder") ); + bSizer2331->Add( m_staticTextDeletionTypeDescription, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - bSizer2011->Add( m_radioBtnVersioning, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + bSizer2331->Add( 0, 0, 1, wxEXPAND, 5 ); - bSizerDelHandling->Add( bSizer2011, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_hyperlinkVersioning = new wxHyperlinkCtrl( m_panelSyncSettings, wxID_ANY, _("Show examples"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); + bSizer2331->Add( m_hyperlinkVersioning, 0, wxALIGN_BOTTOM|wxTOP|wxRIGHT|wxLEFT, 5 ); + + + bSizer2351->Add( bSizer2331, 0, wxALL|wxEXPAND, 5 ); m_panelVersioning = new wxPanel( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelVersioning->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ); @@ -1766,7 +1782,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer156->Add( m_bpButtonSelectAltFolder, 0, wxEXPAND, 5 ); - bSizer191->Add( bSizer156, 0, wxEXPAND|wxALL, 5 ); + bSizer191->Add( bSizer156, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); wxBoxSizer* bSizer198; bSizer198 = new wxBoxSizer( wxHORIZONTAL ); @@ -1778,49 +1794,41 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w wxArrayString m_choiceVersioningStyleChoices; m_choiceVersioningStyle = new wxChoice( m_panelVersioning, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceVersioningStyleChoices, 0 ); m_choiceVersioningStyle->SetSelection( 0 ); - bSizer198->Add( m_choiceVersioningStyle, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer198->Add( 0, 0, 1, wxEXPAND, 5 ); - - m_hyperlink17 = new wxHyperlinkCtrl( m_panelVersioning, wxID_ANY, _("Show examples"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE ); - bSizer198->Add( m_hyperlink17, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer191->Add( bSizer198, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - bSizer192 = new wxBoxSizer( wxHORIZONTAL ); + bSizer198->Add( m_choiceVersioningStyle, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); m_staticTextNamingCvtPart1 = new wxStaticText( m_panelVersioning, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextNamingCvtPart1->Wrap( -1 ); m_staticTextNamingCvtPart1->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - bSizer192->Add( m_staticTextNamingCvtPart1, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer198->Add( m_staticTextNamingCvtPart1, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_staticTextNamingCvtPart2Bold = new wxStaticText( m_panelVersioning, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextNamingCvtPart2Bold->Wrap( -1 ); m_staticTextNamingCvtPart2Bold->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); m_staticTextNamingCvtPart2Bold->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - bSizer192->Add( m_staticTextNamingCvtPart2Bold, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer198->Add( m_staticTextNamingCvtPart2Bold, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_staticTextNamingCvtPart3 = new wxStaticText( m_panelVersioning, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextNamingCvtPart3->Wrap( -1 ); m_staticTextNamingCvtPart3->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - bSizer192->Add( m_staticTextNamingCvtPart3, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer198->Add( m_staticTextNamingCvtPart3, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer191->Add( bSizer192, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + bSizer191->Add( bSizer198, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); m_panelVersioning->SetSizer( bSizer191 ); m_panelVersioning->Layout(); bSizer191->Fit( m_panelVersioning ); - bSizerDelHandling->Add( m_panelVersioning, 1, 0, 5 ); + bSizer2351->Add( m_panelVersioning, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bSizer2361->Add( bSizer2351, 1, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer232->Add( bSizerDelHandling, 0, wxALL|wxEXPAND, 5 ); + bSizer232->Add( bSizer2361, 0, wxEXPAND, 5 ); m_staticline582 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizer232->Add( m_staticline582, 0, wxEXPAND, 5 ); @@ -1876,7 +1884,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_panelSyncSettingsHolder->SetSizer( bSizer276 ); m_panelSyncSettingsHolder->Layout(); bSizer276->Fit( m_panelSyncSettingsHolder ); - m_notebook->AddPage( m_panelSyncSettingsHolder, _("dummy"), false ); + m_notebook->AddPage( m_panelSyncSettingsHolder, _("dummy"), true ); bSizer190->Add( m_notebook, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); @@ -1943,12 +1951,11 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnExRightSideOnly ), NULL, this ); m_checkBoxDetectMove->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleDetectMovedFiles ), NULL, this ); m_hyperlink242->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpDetectMovedFiles ), NULL, this ); - m_bpButtonDeletionType->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleDeletionType ), NULL, this ); - m_radioBtnRecycler->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionRecycler ), NULL, this ); - m_radioBtnPermanent->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionPermanent ), NULL, this ); - m_radioBtnVersioning->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionVersioning ), NULL, this ); + m_toggleBtnRecycler->Connect( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionRecycler ), NULL, this ); + m_toggleBtnPermanent->Connect( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionPermanent ), NULL, this ); + m_toggleBtnVersioning->Connect( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnDeletionVersioning ), NULL, this ); + m_hyperlinkVersioning->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpVersioning ), NULL, this ); m_choiceVersioningStyle->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeSyncOption ), NULL, this ); - m_hyperlink17->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpVersioning ), NULL, this ); m_radioBtnPopupOnErrors->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnErrorPopup ), NULL, this ); m_radioBtnIgnoreErrors->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnErrorIgnore ), NULL, this ); m_buttonOkay->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnOkay ), NULL, this ); @@ -2365,11 +2372,11 @@ CloudSetupDlgGenerated::CloudSetupDlgGenerated( wxWindow* parent, wxWindowID id, m_spinCtrlConnectionCountSftp = new wxSpinCtrl( m_panel411, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 70, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 ); fgSizer1611->Add( m_spinCtrlConnectionCountSftp, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText138111 = new wxStaticText( m_panel411, wxID_ANY, _("Suggested range: [1 - 10]"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText138111->Wrap( -1 ); - m_staticText138111->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + m_staticTextSftpConnectionCountHint = new wxStaticText( m_panel411, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSftpConnectionCountHint->Wrap( -1 ); + m_staticTextSftpConnectionCountHint->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - fgSizer1611->Add( m_staticText138111, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizer1611->Add( m_staticTextSftpConnectionCountHint, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); m_staticText1231111 = new wxStaticText( m_panel411, wxID_ANY, _("SFTP channels per connection:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText1231111->Wrap( -1 ); @@ -2384,24 +2391,6 @@ CloudSetupDlgGenerated::CloudSetupDlgGenerated( wxWindow* parent, wxWindowID id, bSizer1851->Add( fgSizer1611, 0, wxALL, 5 ); - wxBoxSizer* bSizer220; - bSizer220 = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText138112 = new wxStaticText( m_panel411, wxID_ANY, _("Example:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText138112->Wrap( -1 ); - m_staticText138112->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - - bSizer220->Add( m_staticText138112, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticText13811 = new wxStaticText( m_panel411, wxID_ANY, _("2 connections x 10 channels = 20 times faster directory reading"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText13811->Wrap( -1 ); - m_staticText13811->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - - bSizer220->Add( m_staticText13811, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer1851->Add( bSizer220, 0, wxBOTTOM|wxRIGHT|wxLEFT, 10 ); - m_panel411->SetSizer( bSizer1851 ); m_panel411->Layout(); @@ -2457,33 +2446,15 @@ CloudSetupDlgGenerated::CloudSetupDlgGenerated( wxWindow* parent, wxWindowID id, m_spinCtrlConnectionCountFtp = new wxSpinCtrl( m_panel4111, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 70, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 ); fgSizer16111->Add( m_spinCtrlConnectionCountFtp, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText1381111 = new wxStaticText( m_panel4111, wxID_ANY, _("Suggested range: [1 - 10]"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText1381111->Wrap( -1 ); - m_staticText1381111->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); + m_staticTextFtpConnectionCountHint = new wxStaticText( m_panel4111, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextFtpConnectionCountHint->Wrap( -1 ); + m_staticTextFtpConnectionCountHint->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - fgSizer16111->Add( m_staticText1381111, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizer16111->Add( m_staticTextFtpConnectionCountHint, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); bSizer18511->Add( fgSizer16111, 0, wxALL, 5 ); - wxBoxSizer* bSizer2201; - bSizer2201 = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText1381121 = new wxStaticText( m_panel4111, wxID_ANY, _("Example:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText1381121->Wrap( -1 ); - m_staticText1381121->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - - bSizer2201->Add( m_staticText1381121, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticText138113 = new wxStaticText( m_panel4111, wxID_ANY, _("4 connections = 4 times faster directory reading"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText138113->Wrap( -1 ); - m_staticText138113->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - - bSizer2201->Add( m_staticText138113, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer18511->Add( bSizer2201, 0, wxBOTTOM|wxRIGHT|wxLEFT, 10 ); - m_panel4111->SetSizer( bSizer18511 ); m_panel4111->Layout(); @@ -4169,6 +4140,58 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer181->Add( bSizer187, 0, wxALL|wxEXPAND, 5 ); + m_panelDonate = new wxPanel( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panelDonate->SetBackgroundColour( wxColour( 153, 170, 187 ) ); + + wxBoxSizer* bSizer183; + bSizer183 = new wxBoxSizer( wxVERTICAL ); + + m_panel39 = new wxPanel( m_panelDonate, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panel39->SetBackgroundColour( wxColour( 248, 248, 248 ) ); + + wxBoxSizer* bSizer184; + bSizer184 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer184->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_bitmapDonate = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer184->Add( m_bitmapDonate, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + + wxBoxSizer* bSizer178; + bSizer178 = new wxBoxSizer( wxVERTICAL ); + + m_staticTextDonate = new wxStaticText( m_panel39, wxID_ANY, _("If you like FreeFileSync:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE ); + m_staticTextDonate->Wrap( -1 ); + m_staticTextDonate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) ); + m_staticTextDonate->SetForegroundColour( wxColour( 0, 0, 0 ) ); + + bSizer178->Add( m_staticTextDonate, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_buttonDonate = new wxButton( m_panel39, wxID_ANY, _("Support with a donation"), wxDefaultPosition, wxDefaultSize, 0 ); + m_buttonDonate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) ); + m_buttonDonate->SetToolTip( _("http://www.freefilesync.org/donate.php") ); + + bSizer178->Add( m_buttonDonate, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); + + + bSizer184->Add( bSizer178, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + + + bSizer184->Add( 0, 0, 1, wxEXPAND, 5 ); + + + m_panel39->SetSizer( bSizer184 ); + m_panel39->Layout(); + bSizer184->Fit( m_panel39 ); + bSizer183->Add( m_panel39, 0, wxEXPAND|wxALL, 5 ); + + + m_panelDonate->SetSizer( bSizer183 ); + m_panelDonate->Layout(); + bSizer183->Fit( m_panelDonate ); + bSizer181->Add( m_panelDonate, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + m_panelThankYou = new wxPanel( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_panelThankYou->SetBackgroundColour( wxColour( 153, 170, 187 ) ); @@ -4176,7 +4199,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer1831 = new wxBoxSizer( wxVERTICAL ); m_panel391 = new wxPanel( m_panelThankYou, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - m_panel391->SetBackgroundColour( wxColour( 224, 247, 201 ) ); + m_panel391->SetBackgroundColour( wxColour( 248, 248, 248 ) ); wxBoxSizer* bSizer1841; bSizer1841 = new wxBoxSizer( wxHORIZONTAL ); @@ -4185,7 +4208,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer1841->Add( 0, 0, 1, wxEXPAND, 5 ); m_bitmapThanks = new wxStaticBitmap( m_panel391, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - bSizer1841->Add( m_bitmapThanks, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer1841->Add( m_bitmapThanks, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 10 ); wxBoxSizer* bSizer1781; bSizer1781 = new wxBoxSizer( wxVERTICAL ); @@ -4203,7 +4226,7 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer1781->Add( m_buttonShowDonationDetails, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); - bSizer1841->Add( bSizer1781, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer1841->Add( bSizer1781, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); bSizer1841->Add( 0, 0, 1, wxEXPAND, 5 ); @@ -4220,58 +4243,6 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS bSizer1831->Fit( m_panelThankYou ); bSizer181->Add( m_panelThankYou, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - m_panelDonate = new wxPanel( m_panel41, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - m_panelDonate->SetBackgroundColour( wxColour( 153, 170, 187 ) ); - - wxBoxSizer* bSizer183; - bSizer183 = new wxBoxSizer( wxVERTICAL ); - - m_panel39 = new wxPanel( m_panelDonate, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - m_panel39->SetBackgroundColour( wxColour( 221, 221, 255 ) ); - - wxBoxSizer* bSizer184; - bSizer184 = new wxBoxSizer( wxHORIZONTAL ); - - - bSizer184->Add( 0, 0, 1, wxEXPAND, 5 ); - - m_bitmapDonate = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - bSizer184->Add( m_bitmapDonate, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - wxBoxSizer* bSizer178; - bSizer178 = new wxBoxSizer( wxVERTICAL ); - - m_staticTextDonate = new wxStaticText( m_panel39, wxID_ANY, _("If you like FreeFileSync:"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE ); - m_staticTextDonate->Wrap( -1 ); - m_staticTextDonate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) ); - m_staticTextDonate->SetForegroundColour( wxColour( 0, 0, 0 ) ); - - bSizer178->Add( m_staticTextDonate, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 ); - - m_buttonDonate = new wxButton( m_panel39, wxID_ANY, _("Donate with PayPal"), wxDefaultPosition, wxDefaultSize, 0 ); - m_buttonDonate->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) ); - m_buttonDonate->SetToolTip( _("http://www.freefilesync.org/donate.php") ); - - bSizer178->Add( m_buttonDonate, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); - - - bSizer184->Add( bSizer178, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer184->Add( 0, 0, 1, wxEXPAND, 5 ); - - - m_panel39->SetSizer( bSizer184 ); - m_panel39->Layout(); - bSizer184->Fit( m_panel39 ); - bSizer183->Add( m_panel39, 0, wxEXPAND|wxALL, 5 ); - - - m_panelDonate->SetSizer( bSizer183 ); - m_panelDonate->Layout(); - bSizer183->Fit( m_panelDonate ); - bSizer181->Add( m_panelDonate, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - wxBoxSizer* bSizer186; bSizer186 = new wxBoxSizer( wxVERTICAL ); @@ -4414,8 +4385,8 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( AboutDlgGenerated::OnClose ) ); - m_buttonShowDonationDetails->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnShowDonationDetails ), NULL, this ); m_buttonDonate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnDonate ), NULL, this ); + m_buttonShowDonationDetails->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnShowDonationDetails ), NULL, this ); m_buttonClose->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AboutDlgGenerated::OnOK ), NULL, this ); } @@ -4453,8 +4424,10 @@ DownloadProgressDlgGenerated::DownloadProgressDlgGenerated( wxWindow* parent, wx m_gaugeProgress->SetValue( 0 ); bSizer212->Add( m_gaugeProgress, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - m_staticTextDetails = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDetails = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE ); m_staticTextDetails->Wrap( -1 ); + m_staticTextDetails->SetMinSize( wxSize( 550, -1 ) ); + bSizer212->Add( m_staticTextDetails, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h index fae782c6..b9f8c45d 100755 --- a/FreeFileSync/Source/ui/gui_generated.h +++ b/FreeFileSync/Source/ui/gui_generated.h @@ -280,14 +280,12 @@ protected: wxStaticLine* m_staticlineCompHeader; wxPanel* m_panelComparisonSettings; wxStaticText* m_staticText91; - wxStaticBitmap* m_bitmapByTimeSize; wxToggleButton* m_toggleBtnByTimeSize; - wxStaticBitmap* m_bitmapByContent; wxToggleButton* m_toggleBtnByContent; - wxStaticBitmap* m_bitmapBySize; wxToggleButton* m_toggleBtnBySize; wxStaticLine* m_staticline42; - wxTextCtrl* m_textCtrlCompVarDescription; + wxStaticBitmap* m_bitmapCompVariant; + wxStaticText* m_staticTextCompVarDescription; wxStaticLine* m_staticline33; wxCheckBox* m_checkBoxSymlinksInclude; wxRadioButton* m_radioBtnSymlinksFollow; @@ -345,10 +343,10 @@ protected: wxToggleButton* m_toggleBtnUpdate; wxToggleButton* m_toggleBtnCustom; wxStaticLine* m_staticline53; - wxBoxSizer* bSizerSyncConfig; + wxBoxSizer* bSizer233; + wxBoxSizer* bSizerSyncDirections; wxStaticText* m_staticText119; - wxStaticText* m_staticText120; - wxFlexGridSizer* fgSizerSyncDirections; + wxFlexGridSizer* ffgSizer11; wxStaticBitmap* m_bitmapLeftOnly; wxStaticBitmap* m_bitmapLeftNewer; wxStaticBitmap* m_bitmapDifferent; @@ -361,26 +359,29 @@ protected: wxBitmapButton* m_bpButtonConflict; wxBitmapButton* m_bpButtonRightNewer; wxBitmapButton* m_bpButtonRightOnly; + wxStaticText* m_staticText120; + wxStaticText* m_staticText140; + wxStaticText* m_staticText1401; wxStaticBitmap* m_bitmapDatabase; + wxStaticText* m_staticTextSyncVarDescription; wxStaticLine* m_staticline431; wxCheckBox* m_checkBoxDetectMove; wxHyperlinkCtrl* m_hyperlink242; - wxStaticLine* m_staticline531; - wxTextCtrl* m_textCtrlSyncVarDescription; wxStaticLine* m_staticline54; - wxBoxSizer* bSizerDelHandling; + wxBoxSizer* bSizer2361; wxStaticText* m_staticText87; - wxBitmapButton* m_bpButtonDeletionType; - wxRadioButton* m_radioBtnRecycler; - wxRadioButton* m_radioBtnPermanent; - wxRadioButton* m_radioBtnVersioning; + wxToggleButton* m_toggleBtnRecycler; + wxToggleButton* m_toggleBtnPermanent; + wxToggleButton* m_toggleBtnVersioning; + wxStaticLine* m_staticline531; + wxStaticBitmap* m_bitmapDeletionType; + wxStaticText* m_staticTextDeletionTypeDescription; + wxHyperlinkCtrl* m_hyperlinkVersioning; wxPanel* m_panelVersioning; FolderHistoryBox* m_versioningFolderPath; wxButton* m_buttonSelectVersioningFolder; wxStaticText* m_staticText93; wxChoice* m_choiceVersioningStyle; - wxHyperlinkCtrl* m_hyperlink17; - wxBoxSizer* bSizer192; wxStaticText* m_staticTextNamingCvtPart1; wxStaticText* m_staticTextNamingCvtPart2Bold; wxStaticText* m_staticTextNamingCvtPart3; @@ -432,12 +433,11 @@ protected: virtual void OnExRightSideOnly( wxCommandEvent& event ) { event.Skip(); } virtual void OnToggleDetectMovedFiles( wxCommandEvent& event ) { event.Skip(); } virtual void OnHelpDetectMovedFiles( wxHyperlinkEvent& event ) { event.Skip(); } - virtual void OnToggleDeletionType( wxCommandEvent& event ) { event.Skip(); } virtual void OnDeletionRecycler( wxCommandEvent& event ) { event.Skip(); } virtual void OnDeletionPermanent( wxCommandEvent& event ) { event.Skip(); } virtual void OnDeletionVersioning( wxCommandEvent& event ) { event.Skip(); } - virtual void OnChangeSyncOption( wxCommandEvent& event ) { event.Skip(); } virtual void OnHelpVersioning( wxHyperlinkEvent& event ) { event.Skip(); } + virtual void OnChangeSyncOption( wxCommandEvent& event ) { event.Skip(); } virtual void OnErrorPopup( wxCommandEvent& event ) { event.Skip(); } virtual void OnErrorIgnore( wxCommandEvent& event ) { event.Skip(); } virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); } @@ -542,12 +542,10 @@ protected: wxPanel* m_panel411; wxStaticText* m_staticText12341; wxSpinCtrl* m_spinCtrlConnectionCountSftp; - wxStaticText* m_staticText138111; + wxStaticText* m_staticTextSftpConnectionCountHint; wxStaticText* m_staticText1231111; wxSpinCtrl* m_spinCtrlChannelCountSftp; wxButton* m_button42; - wxStaticText* m_staticText138112; - wxStaticText* m_staticText13811; wxBoxSizer* bSizerFtpTweaks; wxStaticLine* m_staticline5711; wxStaticBitmap* m_bitmapSpeedFtp; @@ -557,9 +555,7 @@ protected: wxPanel* m_panel4111; wxStaticText* m_staticText123411; wxSpinCtrl* m_spinCtrlConnectionCountFtp; - wxStaticText* m_staticText1381111; - wxStaticText* m_staticText1381121; - wxStaticText* m_staticText138113; + wxStaticText* m_staticTextFtpConnectionCountHint; wxStaticLine* m_staticline12; wxBoxSizer* bSizerStdButtons; wxButton* m_buttonOkay; @@ -1029,16 +1025,16 @@ protected: wxHyperlinkCtrl* m_hyperlink101; wxHyperlinkCtrl* m_hyperlink18; wxHyperlinkCtrl* m_hyperlink9; - wxPanel* m_panelThankYou; - wxPanel* m_panel391; - wxStaticBitmap* m_bitmapThanks; - wxStaticText* m_staticTextThanks; - wxButton* m_buttonShowDonationDetails; wxPanel* m_panelDonate; wxPanel* m_panel39; wxStaticBitmap* m_bitmapDonate; wxStaticText* m_staticTextDonate; wxButton* m_buttonDonate; + wxPanel* m_panelThankYou; + wxPanel* m_panel391; + wxStaticBitmap* m_bitmapThanks; + wxStaticText* m_staticTextThanks; + wxButton* m_buttonShowDonationDetails; wxStaticText* m_staticText94; wxStaticBitmap* m_bitmapHomepage; wxHyperlinkCtrl* m_hyperlink1; @@ -1058,8 +1054,8 @@ protected: // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } - virtual void OnShowDonationDetails( wxCommandEvent& event ) { event.Skip(); } virtual void OnDonate( wxCommandEvent& event ) { event.Skip(); } + virtual void OnShowDonationDetails( wxCommandEvent& event ) { event.Skip(); } virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp index 0200defb..3a61dcfd 100755 --- a/FreeFileSync/Source/ui/main_dlg.cpp +++ b/FreeFileSync/Source/ui/main_dlg.cpp @@ -2282,7 +2282,7 @@ void MainDialog::onMainGridContextRim(bool leftSide) ++it) { //translate default external apps on the fly: 1. "open in explorer" 2. "start directly" - wxString description = zen::implementation::translate(it->first); + wxString description = zen::translate(it->first); if (description.empty()) description = L" "; //wxWidgets doesn't like empty items diff --git a/FreeFileSync/Source/ui/on_completion_box.cpp b/FreeFileSync/Source/ui/on_completion_box.cpp index 0989b28d..e5c91321 100755 --- a/FreeFileSync/Source/ui/on_completion_box.cpp +++ b/FreeFileSync/Source/ui/on_completion_box.cpp @@ -102,7 +102,7 @@ Zstring OnCompletionBox::getValue() const { auto value = trimCpy(copyStringTo<std::wstring>(GetValue())); - if (value == implementation::translate(getCmdTxtCloseProgressDlg())) //undo translation for config file storage + if (value == zen::translate(getCmdTxtCloseProgressDlg())) //undo translation for config file storage value = getCmdTxtCloseProgressDlg(); return utfTo<Zstring>(value); @@ -114,7 +114,7 @@ void OnCompletionBox::setValue(const Zstring& value) auto tmp = trimCpy(utfTo<std::wstring>(value)); if (tmp == getCmdTxtCloseProgressDlg()) - tmp = implementation::translate(getCmdTxtCloseProgressDlg()); //have this symbolic constant translated properly + tmp = zen::translate(getCmdTxtCloseProgressDlg()); //have this symbolic constant translated properly setValueAndUpdateList(tmp); } @@ -128,7 +128,7 @@ void OnCompletionBox::setValueAndUpdateList(const std::wstring& value) std::deque<std::wstring> items; //1. special command - items.push_back(implementation::translate(getCmdTxtCloseProgressDlg())); + items.push_back(zen::translate(getCmdTxtCloseProgressDlg())); //2. built in commands for (const auto& item : defaultCommands_) diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp index 550f7749..62ba774d 100755 --- a/FreeFileSync/Source/ui/small_dlgs.cpp +++ b/FreeFileSync/Source/ui/small_dlgs.cpp @@ -62,7 +62,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) { m_panelThankYou->Hide(); - m_bitmapDonate->SetBitmap(getResourceImage(L"paypal")); + m_bitmapDonate->SetBitmap(getResourceImage(L"freefilesync-heart")); setRelativeFontSize(*m_staticTextDonate, 1.25); setRelativeFontSize(*m_buttonDonate, 1.25); } @@ -89,7 +89,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) //build information - wxString build = __TDATE__; + wxString build = formatTime<std::wstring>(FORMAT_DATE, getCompileTime()); build += L" - Unicode"; #ifndef wxUSE_UNICODE #error what is going on? @@ -102,6 +102,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) L" x64"; #endif + GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize() //generate logo: put *after* first Fit() @@ -112,7 +113,8 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent) *wxBLACK); //accessibility: align foreground/background colors! wxImage buildImg = createImageFromText(replaceCpy(_("Build: %x"), L"%x", build), *wxNORMAL_FONT, - *wxBLACK); + *wxBLACK, + ImageStackAlignment::CENTER); wxImage versionImage = stackImages(appnameImg, buildImg, ImageStackLayout::VERTICAL, ImageStackAlignment::CENTER, 0); const int BORDER_SIZE = 5; @@ -650,7 +652,7 @@ void OptionsDlg::setExtApp(const xmlAccess::ExternalApps& extApp) auto extAppTmp = extApp; erase_if(extAppTmp, [](auto& entry) { return entry.first.empty() && entry.second.empty(); }); - extAppTmp.resize(extAppTmp.size() + 1); //append empty row to facilitate insertions + extAppTmp.emplace_back(); //append empty row to facilitate insertions by user const int rowCount = m_gridCustomCommand->GetNumberRows(); if (rowCount > 0) @@ -661,7 +663,7 @@ void OptionsDlg::setExtApp(const xmlAccess::ExternalApps& extApp) { const int row = it - extAppTmp.begin(); - const std::wstring description = zen::implementation::translate(it->first); + const std::wstring description = zen::translate(it->first); if (description != it->first) //remember english description to save in GlobalSettings.xml later rather than hard-code translation descriptionTransToEng[description] = it->first; @@ -905,9 +907,10 @@ ReturnActivationDlg zen::showActivationDialog(wxWindow* parent, const std::wstri class DownloadProgressWindow::Impl : public DownloadProgressDlgGenerated { public: - Impl(wxWindow* parent, const Zstring& fileName, uint64_t fileSize); + Impl(wxWindow* parent, int64_t fileSizeTotal); - void notifyProgress(uint64_t delta) { bytesCurrent_ += delta; } + void notifyNewFile (const Zstring& filePath) { filePath_ = filePath; } + void notifyProgress(int64_t delta) { bytesCurrent_ += delta; } void requestUiRefresh() //throw CancelPressed { @@ -931,18 +934,21 @@ private: m_staticTextHeader->SetLabel(_("Downloading update...") + L" " + numberTo<std::wstring>(numeric::round(fraction * 100)) + L"% (" + filesizeToShortString(bytesCurrent_) + L")"); m_gaugeProgress->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE)); + + m_staticTextDetails->SetLabel(utfTo<std::wstring>(filePath_)); } bool cancelled_ = false; - uint64_t bytesCurrent_ = 0; - const uint64_t bytesTotal_; + int64_t bytesCurrent_ = 0; + const int64_t bytesTotal_; + Zstring filePath_; const int GAUGE_FULL_RANGE = 1000000; }; -DownloadProgressWindow::Impl::Impl(wxWindow* parent, const Zstring& filePath, uint64_t fileSize) : +DownloadProgressWindow::Impl::Impl(wxWindow* parent, int64_t fileSizeTotal) : DownloadProgressDlgGenerated(parent), - bytesTotal_(fileSize) + bytesTotal_(fileSizeTotal) { setStandardButtonLayout(*bSizerStdButtons, StdButtons().setCancel(m_buttonCancel)); @@ -953,8 +959,6 @@ DownloadProgressWindow::Impl::Impl(wxWindow* parent, const Zstring& filePath, ui m_gaugeProgress->SetRange(GAUGE_FULL_RANGE); - m_staticTextDetails->SetLabel(utfTo<std::wstring>(filePath)); - updateGui(); GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize() @@ -966,10 +970,11 @@ DownloadProgressWindow::Impl::Impl(wxWindow* parent, const Zstring& filePath, ui } -zen::DownloadProgressWindow::DownloadProgressWindow(wxWindow* parent, const Zstring& filePath, uint64_t fileSize) : - pimpl_(new DownloadProgressWindow::Impl(parent, filePath, fileSize)) {} +zen::DownloadProgressWindow::DownloadProgressWindow(wxWindow* parent, int64_t fileSizeTotal) : + pimpl_(new DownloadProgressWindow::Impl(parent, fileSizeTotal)) {} zen::DownloadProgressWindow::~DownloadProgressWindow() { pimpl_->Destroy(); } -void zen::DownloadProgressWindow::notifyProgress(uint64_t delta) { pimpl_->notifyProgress(delta); } -void zen::DownloadProgressWindow::requestUiRefresh() { pimpl_->requestUiRefresh(); } //throw CancelPressed +void zen::DownloadProgressWindow::notifyNewFile(const Zstring& filePath) { pimpl_->notifyNewFile(filePath); } +void zen::DownloadProgressWindow::notifyProgress(int64_t delta) { pimpl_->notifyProgress(delta); } +void zen::DownloadProgressWindow::requestUiRefresh() { pimpl_->requestUiRefresh(); } //throw CancelPressed diff --git a/FreeFileSync/Source/ui/small_dlgs.h b/FreeFileSync/Source/ui/small_dlgs.h index c7c3f9c4..b62bf1ab 100755 --- a/FreeFileSync/Source/ui/small_dlgs.h +++ b/FreeFileSync/Source/ui/small_dlgs.h @@ -63,12 +63,13 @@ ReturnActivationDlg showActivationDialog(wxWindow* parent, const std::wstring& l class DownloadProgressWindow //temporary progress info => life-time: stack { public: - DownloadProgressWindow(wxWindow* parent, const Zstring& filePath, uint64_t fileSize); + DownloadProgressWindow(wxWindow* parent, int64_t fileSizeTotal); ~DownloadProgressWindow(); struct CancelPressed {}; + void notifyNewFile(const Zstring& filePath); + void notifyProgress(int64_t delta); void requestUiRefresh(); //throw CancelPressed - void notifyProgress(uint64_t delta); private: class Impl; diff --git a/FreeFileSync/Source/ui/sync_cfg.cpp b/FreeFileSync/Source/ui/sync_cfg.cpp index e281fb0d..249f614d 100755 --- a/FreeFileSync/Source/ui/sync_cfg.cpp +++ b/FreeFileSync/Source/ui/sync_cfg.cpp @@ -29,9 +29,6 @@ using namespace xmlAccess; namespace { -void toggleDeletionPolicy(DeletionPolicy& deletionPolicy); - - class ConfigDialog : public ConfigDlgGenerated { public: @@ -123,8 +120,6 @@ private: void OnDeletionRecycler (wxCommandEvent& event) override { handleDeletion_ = DeletionPolicy::RECYCLER; updateSyncGui(); } void OnDeletionVersioning (wxCommandEvent& event) override { handleDeletion_ = DeletionPolicy::VERSIONING; updateSyncGui(); } - void OnToggleDeletionType(wxCommandEvent& event) override { toggleDeletionPolicy(handleDeletion_); updateSyncGui(); } - void OnHelpDetectMovedFiles(wxHyperlinkEvent& event) override { displayHelpEntry(L"synchronization-settings", this); } void OnHelpVersioning (wxHyperlinkEvent& event) override { displayHelpEntry(L"versioning", this); } @@ -259,10 +254,6 @@ ConfigDialog::ConfigDialog(wxWindow* parent, m_toggleBtnByContent ->SetToolTip(getCompVariantDescription(CompareVariant::CONTENT)); m_toggleBtnBySize ->SetToolTip(getCompVariantDescription(CompareVariant::SIZE)); - m_bitmapByTimeSize->SetToolTip(getCompVariantDescription(CompareVariant::TIME_SIZE)); - m_bitmapByContent ->SetToolTip(getCompVariantDescription(CompareVariant::CONTENT)); - m_bitmapBySize ->SetToolTip(getCompVariantDescription(CompareVariant::SIZE)); - //------------- filter panel -------------------------- assert(!contains(m_buttonClear->GetLabel(), L"&C") && !contains(m_buttonClear->GetLabel(), L"&c")); //gazillionth wxWidgets bug on OS X: Command + C mistakenly hits "&C" access key! @@ -306,12 +297,16 @@ ConfigDialog::ConfigDialog(wxWindow* parent, setRelativeFontSize(*m_toggleBtnUpdate, 1.25); setRelativeFontSize(*m_toggleBtnCustom, 1.25); + m_toggleBtnRecycler ->SetToolTip(_("Back up deleted and overwritten files in the recycle bin")); + m_toggleBtnPermanent ->SetToolTip(_("Delete or overwrite files permanently")); + m_toggleBtnVersioning->SetToolTip(_("Move files to a user-defined folder")); + enumVersioningStyle_. add(VersioningStyle::REPLACE, _("Replace"), _("Move files and replace if existing")). add(VersioningStyle::ADD_TIMESTAMP, _("Time stamp"), _("Append a time stamp to each file name")); //use spacer to keep dialog height stable, no matter if versioning options are visible - bSizerDelHandling->Add(0, m_panelVersioning->GetSize().GetHeight()); + //bSizerDelHandling->Add(0, m_panelVersioning->GetSize().GetHeight()); //----------------------------------------------------- @@ -528,6 +523,15 @@ void ConfigDialog::updateCompGui() m_notebook->SetPageImage(static_cast<size_t>(SyncConfigPanel::COMPARISON), static_cast<int>(m_checkBoxUseLocalCmpOptions->GetValue() ? ConfigTypeImage::COMPARISON : ConfigTypeImage::COMPARISON_GREY)); + auto setBitmap = [&](wxStaticBitmap& bmpCtrl, bool active, const wxBitmap& bmp) + { + if (active && + m_checkBoxUseLocalCmpOptions->GetValue()) //help wxWidgets a little to render inactive config state (need on Windows, NOT on Linux!) + bmpCtrl.SetBitmap(bmp); + else + bmpCtrl.SetBitmap(greyScale(bmp)); + }; + //update toggle buttons -> they have no parameter-ownership at all! m_toggleBtnByTimeSize->SetValue(false); m_toggleBtnBySize ->SetValue(false); @@ -538,29 +542,21 @@ void ConfigDialog::updateCompGui() { case CompareVariant::TIME_SIZE: m_toggleBtnByTimeSize->SetValue(true); + setBitmap(*m_bitmapCompVariant, true, getResourceImage(L"file-time")); break; case CompareVariant::CONTENT: m_toggleBtnByContent->SetValue(true); + setBitmap(*m_bitmapCompVariant, true, getResourceImage(L"file-content")); break; case CompareVariant::SIZE: m_toggleBtnBySize->SetValue(true); + setBitmap(*m_bitmapCompVariant, true, getResourceImage(L"file-size")); break; } - auto setBitmap = [&](wxStaticBitmap& bmpCtrl, bool active, const wxBitmap& bmp) - { - if (active && - m_checkBoxUseLocalCmpOptions->GetValue()) //help wxWidgets a little to render inactive config state (need on Windows, NOT on Linux!) - bmpCtrl.SetBitmap(bmp); - else - bmpCtrl.SetBitmap(greyScale(bmp)); - }; - setBitmap(*m_bitmapByTimeSize, localCmpVar_ == CompareVariant::TIME_SIZE, getResourceImage(L"file-time")); - setBitmap(*m_bitmapByContent, localCmpVar_ == CompareVariant::CONTENT, getResourceImage(L"file-content")); - setBitmap(*m_bitmapBySize, localCmpVar_ == CompareVariant::SIZE, getResourceImage(L"file-size")); - //active variant description: - setText(*m_textCtrlCompVarDescription, L"\n" + getCompVariantDescription(localCmpVar_)); + setText(*m_staticTextCompVarDescription, getCompVariantDescription(localCmpVar_)); + m_staticTextCompVarDescription->Wrap(400); //needs to be reapplied after SetLabel() m_radioBtnSymlinksDirect->Enable(m_checkBoxSymlinksInclude->GetValue()); m_radioBtnSymlinksFollow->Enable(m_checkBoxSymlinksInclude->GetValue()); @@ -836,23 +832,6 @@ void updateSyncDirectionIcons(const DirectionConfig& directionCfg, } -void toggleDeletionPolicy(DeletionPolicy& deletionPolicy) -{ - switch (deletionPolicy) - { - case DeletionPolicy::PERMANENT: - deletionPolicy = DeletionPolicy::VERSIONING; - break; - case DeletionPolicy::RECYCLER: - deletionPolicy = DeletionPolicy::PERMANENT; - break; - case DeletionPolicy::VERSIONING: - deletionPolicy = DeletionPolicy::RECYCLER; - break; - } -} - - std::shared_ptr<const SyncConfig> ConfigDialog::getSyncConfig() const { if (!m_checkBoxUseLocalSyncOptions->GetValue()) @@ -904,21 +883,20 @@ void ConfigDialog::updateSyncGui() m_checkBoxDetectMove->Enable(detectMovedFilesSelectable(directionCfg_)); m_checkBoxDetectMove->SetValue(detectMovedFilesEnabled(directionCfg_)); //parameter NOT owned by checkbox! - auto setBitmap = [&](wxStaticBitmap& bmpCtrl, bool active, const wxBitmap& bmp) + auto setBitmap = [&](wxStaticBitmap& bmpCtrl, const wxBitmap& bmp) { - if (active && - m_checkBoxUseLocalSyncOptions->GetValue()) //help wxWidgets a little to render inactive config state (need on Windows, NOT on Linux!) + if (m_checkBoxUseLocalSyncOptions->GetValue()) //help wxWidgets a little to render inactive config state (need on Windows, NOT on Linux!) bmpCtrl.SetBitmap(bmp); else bmpCtrl.SetBitmap(greyScale(bmp)); }; //display only relevant sync options - m_bitmapDatabase ->Show(directionCfg_.var == DirectionConfig::TWO_WAY); - fgSizerSyncDirections->Show(directionCfg_.var != DirectionConfig::TWO_WAY); + m_bitmapDatabase ->Show(directionCfg_.var == DirectionConfig::TWO_WAY); + bSizerSyncDirections->Show(directionCfg_.var != DirectionConfig::TWO_WAY); if (directionCfg_.var == DirectionConfig::TWO_WAY) - setBitmap(*m_bitmapDatabase, true, getResourceImage(L"database")); + setBitmap(*m_bitmapDatabase, getResourceImage(L"database")); else { const CompareVariant activeCmpVar = m_checkBoxUseLocalCmpOptions->GetValue() ? localCmpVar_ : globalCfg_.cmpConfig.compareVar; @@ -933,7 +911,8 @@ void ConfigDialog::updateSyncGui() } //active variant description: - setText(*m_textCtrlSyncVarDescription, L"\n" + getSyncVariantDescription(directionCfg_.var)); + setText(*m_staticTextSyncVarDescription, getSyncVariantDescription(directionCfg_.var)); + m_staticTextSyncVarDescription->Wrap(220); //needs to be reapplied after SetLabel() //update toggle buttons -> they have no parameter-ownership at all! m_toggleBtnTwoWay->SetValue(false); @@ -958,32 +937,34 @@ void ConfigDialog::updateSyncGui() break; } + m_toggleBtnRecycler ->SetValue(false); + m_toggleBtnPermanent ->SetValue(false); + m_toggleBtnVersioning->SetValue(false); + switch (handleDeletion_) { - case DeletionPolicy::PERMANENT: - m_radioBtnPermanent->SetValue(true); - - m_bpButtonDeletionType->SetBitmapLabel(getResourceImage(L"delete_permanently")); - m_bpButtonDeletionType->SetToolTip(_("Delete or overwrite files permanently")); - break; case DeletionPolicy::RECYCLER: - m_radioBtnRecycler->SetValue(true); - - m_bpButtonDeletionType->SetBitmapLabel(getResourceImage(L"delete_recycler")); - m_bpButtonDeletionType->SetToolTip(_("Back up deleted and overwritten files in the recycle bin")); + m_toggleBtnRecycler->SetValue(true); + setBitmap(*m_bitmapDeletionType, getResourceImage(L"delete_recycler")); + setText(*m_staticTextDeletionTypeDescription, _("Back up deleted and overwritten files in the recycle bin")); + break; + case DeletionPolicy::PERMANENT: + m_toggleBtnPermanent->SetValue(true); + setBitmap(*m_bitmapDeletionType, getResourceImage(L"delete_permanently")); + setText(*m_staticTextDeletionTypeDescription, _("Delete or overwrite files permanently")); break; case DeletionPolicy::VERSIONING: - m_radioBtnVersioning->SetValue(true); - - m_bpButtonDeletionType->SetBitmapLabel(getResourceImage(L"delete_versioning")); - m_bpButtonDeletionType->SetToolTip(_("Move files to a user-defined folder")); + m_toggleBtnVersioning->SetValue(true); + setBitmap(*m_bitmapDeletionType, getResourceImage(L"delete_versioning_small")); + setText(*m_staticTextDeletionTypeDescription, _("Move files to a user-defined folder")); break; } - m_bpButtonDeletionType->SetBitmapDisabled(greyScale(m_bpButtonDeletionType->GetBitmap())); //fix wxWidgets' all-too-clever multi-state! + //m_staticTextDeletionTypeDescription->Wrap(200); //needs to be reapplied after SetLabel() const bool versioningSelected = handleDeletion_ == DeletionPolicy::VERSIONING; - m_panelVersioning->Show(versioningSelected); + m_panelVersioning ->Show(versioningSelected); + m_hyperlinkVersioning->Show(versioningSelected); if (versioningSelected) { diff --git a/FreeFileSync/Source/ui/version_check.cpp b/FreeFileSync/Source/ui/version_check.cpp index 45f166bb..598873e4 100755 --- a/FreeFileSync/Source/ui/version_check.cpp +++ b/FreeFileSync/Source/ui/version_check.cpp @@ -29,7 +29,6 @@ namespace const wchar_t ffsUpdateCheckUserAgent[] = L"FFS-Update-Check"; - std::wstring getIso639Language() { assert(std::this_thread::get_id() == mainThreadId); //this function is not thread-safe, consider wxWidgets usage @@ -67,7 +66,8 @@ std::vector<std::pair<std::string, std::string>> geHttpPostParameters() std::vector<std::pair<std::string, std::string>> params; params.emplace_back("ffs_version", zen::ffsVersion); - params.emplace_back("ffs_type", isPortableVersion() ? "Portable" : "Local"); + params.emplace_back("installation_type", isPortableVersion() ? "Portable" : "Local"); + params.emplace_back("os_name", "Linux"); @@ -198,25 +198,33 @@ void zen::checkForUpdateNow(wxWindow* parent, std::string& lastOnlineVersion) { lastOnlineVersion = "Unknown"; - switch (showConfirmationDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). - setTitle(_("Check for Program Updates")). - setMainInstructions(_("Cannot find current FreeFileSync version number online. A newer version is likely available. Check manually now?")). - setDetailInstructions(e.toString()), _("&Check"))) + switch (showQuestionDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). + setTitle(_("Check for Program Updates")). + setMainInstructions(_("Cannot find current FreeFileSync version number online. A newer version is likely available. Check manually now?")). + setDetailInstructions(e.toString()), _("&Check"), _("&Retry"))) { - case ConfirmationButton::ACCEPT: + case QuestionButton2::YES: wxLaunchDefaultBrowser(L"http://www.freefilesync.org/get_latest.php"); break; - case ConfirmationButton::CANCEL: + case QuestionButton2::NO: //retry + checkForUpdateNow(parent, lastOnlineVersion); //note: retry via recursion!!! + break; + case QuestionButton2::CANCEL: break; } } else - { - showNotificationDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). - setTitle(_("Check for Program Updates")). - setMainInstructions(replaceCpy(_("Unable to connect to %x."), L"%x", L"www.freefilesync.org")). - setDetailInstructions(e.toString())); - } + switch (showConfirmationDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). + setTitle(_("Check for Program Updates")). + setMainInstructions(replaceCpy(_("Unable to connect to %x."), L"%x", L"www.freefilesync.org")). + setDetailInstructions(e.toString()), _("&Retry"))) + { + case ConfirmationButton::ACCEPT: //retry + checkForUpdateNow(parent, lastOnlineVersion); //note: retry via recursion!!! + break; + case ConfirmationButton::CANCEL: + break; + } } } @@ -279,16 +287,19 @@ void zen::periodicUpdateCheckEval(wxWindow* parent, time_t& lastUpdateCheck, std { lastOnlineVersion = "Unknown"; - switch (showConfirmationDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). - setTitle(_("Check for Program Updates")). - setMainInstructions(_("Cannot find current FreeFileSync version number online. A newer version is likely available. Check manually now?")). - setDetailInstructions(result.error->toString()), - _("&Check"))) + switch (showQuestionDialog(parent, DialogInfoType::ERROR2, PopupDialogCfg(). + setTitle(_("Check for Program Updates")). + setMainInstructions(_("Cannot find current FreeFileSync version number online. A newer version is likely available. Check manually now?")). + setDetailInstructions(result.error->toString()), + _("&Check"), _("&Retry"))) { - case ConfirmationButton::ACCEPT: + case QuestionButton2::YES: wxLaunchDefaultBrowser(L"http://www.freefilesync.org/get_latest.php"); break; - case ConfirmationButton::CANCEL: + case QuestionButton2::NO: //retry + periodicUpdateCheckEval(parent, lastUpdateCheck, lastOnlineVersion, resultAsync); //note: retry via recursion!!! + break; + case QuestionButton2::CANCEL: break; } } diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h index 88471d98..fc23b8d3 100755 --- a/FreeFileSync/Source/version/version.h +++ b/FreeFileSync/Source/version/version.h @@ -3,7 +3,7 @@ namespace zen { -const char ffsVersion[] = "9.3"; //internal linkage! +const char ffsVersion[] = "9.4"; //internal linkage! const char FFS_VERSION_SEPARATOR = '.'; } diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp index 90945a44..bb5cd6c3 100755 --- a/wx+/image_tools.cpp +++ b/wx+/image_tools.cpp @@ -130,22 +130,43 @@ void calcAlphaForBlackWhiteImage(wxImage& image) //assume black text on white ba } -wxSize getTextExtent(const wxString& text, const wxFont& font) +std::vector<std::pair<wxString, wxSize>> getTextExtentInfo(const wxString& text, const wxFont& font) { wxMemoryDC dc; //the context used for bitmaps dc.SetFont(font); //the font parameter of GetMultiLineTextExtent() is not evalated on OS X, wxWidgets 2.9.5, so apply it to the DC directly! - return dc.GetMultiLineTextExtent(replaceCpy(text, L"&", L"", false)); //remove accelerator + + std::vector<std::pair<wxString, wxSize>> lineInfo; //text + extent + for (const wxString& line : split(text, L"\n", SplitType::ALLOW_EMPTY)) + lineInfo.emplace_back(line, line.empty() ? wxSize() : dc.GetTextExtent(line)); + + return lineInfo; } } -wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col) +wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign) { - //wxDC::DrawLabel() doesn't respect alpha channel => calculate alpha values manually: + //assert(!contains(text, L"&")); //accelerator keys not supported here + wxString textFmt = replaceCpy(text, L"&", L"", false); - if (text.empty()) + //for some reason wxDC::DrawText messes up "weak" bidi characters even when wxLayout_RightToLeft is set! (--> arrows in hebrew/arabic) + //=> use mark characters instead: + const wchar_t rtlMark = L'\u200F'; //UTF-8: E2 80 8F + if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) + textFmt = rtlMark + textFmt + rtlMark; + + const std::vector<std::pair<wxString, wxSize>> lineInfo = getTextExtentInfo(textFmt, font); + + int maxWidth = 0; + int lineHeight = 0; + for (const auto& li : lineInfo) + { + maxWidth = std::max(maxWidth, li.second.GetWidth()); + lineHeight = std::max(lineHeight, li.second.GetHeight()); //wxWidgets comment "GetTextExtent will return 0 for empty string" + } + if (maxWidth == 0 || lineHeight == 0) return wxImage(); - wxBitmap newBitmap(getTextExtent(text, font)); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes + wxBitmap newBitmap(maxWidth, lineHeight * lineInfo.size()); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes { wxMemoryDC dc(newBitmap); dc.SetBackground(*wxWHITE_BRUSH); @@ -155,22 +176,31 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const dc.SetTextBackground(*wxWHITE); // dc.SetFont(font); - //assert(!contains(text, L"&")); //accelerator keys not supported here; see also getTextExtent() - wxString textFmt = replaceCpy(text, L"&", L"", false); - - //for some reason wxDC::DrawText messes up "weak" bidi characters even when wxLayout_RightToLeft is set! (--> arrows in hebrew/arabic) - //=> use mark characters instead: - const wchar_t rtlMark = L'\u200F'; //UTF-8: E2 80 8F - if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft) - textFmt = rtlMark + textFmt + rtlMark; - - dc.DrawText(textFmt, wxPoint()); + int posY = 0; + for (const auto& li : lineInfo) + { + if (!li.first.empty()) + switch (textAlign) + { + case ImageStackAlignment::LEFT: + dc.DrawText(li.first, wxPoint(0, posY)); + break; + case ImageStackAlignment::RIGHT: + dc.DrawText(li.first, wxPoint(maxWidth - li.second.GetWidth(), posY)); + break; + case ImageStackAlignment::CENTER: + dc.DrawText(li.first, wxPoint((maxWidth - li.second.GetWidth()) / 2, posY)); + break; + } + + posY += lineHeight; + } } + //wxDC::DrawLabel() doesn't respect alpha channel => calculate alpha values manually: wxImage output(newBitmap.ConvertToImage()); output.SetAlpha(); - //calculate alpha channel calcAlphaForBlackWhiteImage(output); //apply actual text color diff --git a/wx+/image_tools.h b/wx+/image_tools.h index cd0e28f0..a1fed061 100755 --- a/wx+/image_tools.h +++ b/wx+/image_tools.h @@ -32,7 +32,7 @@ enum class ImageStackAlignment }; wxImage stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout dir, ImageStackAlignment align, int gap = 0); -wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col); +wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign = ImageStackAlignment::LEFT); //CENTER/LEFT/RIGHT wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground); //merge diff --git a/wx+/std_button_layout.h b/wx+/std_button_layout.h index fa4a269e..0f0d607f 100755 --- a/wx+/std_button_layout.h +++ b/wx+/std_button_layout.h @@ -115,7 +115,7 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons) sizer.Add(spaceRimH, 0); //OS X: there should be at least one button following the gap after the "dangerous" no-button - assert(buttonsTmp.btnYes); + assert(buttonsTmp.btnYes || buttonsTmp.btnCancel); } } diff --git a/zen/basic_math.h b/zen/basic_math.h index 722722a5..22f29ca7 100755 --- a/zen/basic_math.h +++ b/zen/basic_math.h @@ -24,10 +24,9 @@ template <class T> T min(T a, T b, T c); template <class T> T max(T a, T b, T c); template <class T> bool isNull(T value); -template <class T> -void clamp(T& val, T minVal, T maxVal); //make sure minVal <= val && val <= maxVal -template <class T> -T clampCpy(T val, T minVal, T maxVal); +template <class T> void clamp(T& val, T minVal, T maxVal); //make sure minVal <= val && val <= maxVal +template <class T> T clampCpy(T val, T minVal, T maxVal); +//std::clamp() available with C++17 template <class T, class InputIterator> //precondition: range must be sorted! auto nearMatch(const T& val, InputIterator first, InputIterator last); @@ -64,6 +63,8 @@ const double pi = 3.14159265358979323846; const double e = 2.71828182845904523536; const double sqrt2 = 1.41421356237309504880; const double ln2 = 0.693147180559945309417; + +//static_assert(pi + e + sqrt2 + ln2 == 7.9672352249818781, "whoopsie"); //---------------------------------------------------------------------------------- @@ -286,17 +287,16 @@ template <class RandomAccessIterator> inline double median(RandomAccessIterator first, RandomAccessIterator last) //note: invalidates input range! { const size_t n = last - first; - if (n > 0) - { - std::nth_element(first, first + n / 2, last); //complexity: O(n) - const double midVal = *(first + n / 2); + if (n == 0) + return 0; - if (n % 2 != 0) - return midVal; - else //n is even and >= 2 in this context: return mean of two middle values - return 0.5 * (*std::max_element(first, first + n / 2) + midVal); //this operation is the reason why median() CANNOT support a comparison predicate!!! - } - return 0; + std::nth_element(first, first + n / 2, last); //complexity: O(n) + const double midVal = *(first + n / 2); + + if (n % 2 != 0) + return midVal; + else //n is even and >= 2 in this context: return mean of two middle values + return 0.5 * (*std::max_element(first, first + n / 2) + midVal); //this operation is the reason why median() CANNOT support a comparison predicate!!! } @@ -304,25 +304,22 @@ template <class RandomAccessIterator> inline double mad(RandomAccessIterator first, RandomAccessIterator last) //note: invalidates input range! { //http://en.wikipedia.org/wiki/Median_absolute_deviation - const size_t n = last - first; - if (n > 0) - { - const double m = median(first, last); + if (n == 0) + return 0; - //the second median needs to operate on absolute residuals => avoid transforming input range which may have less than double precision! + const double m = median(first, last); - auto lessMedAbs = [m](double lhs, double rhs) { return abs(lhs - m) < abs(rhs - m); }; + //the second median needs to operate on absolute residuals => avoid transforming input range which may have less than double precision! + auto lessMedAbs = [m](double lhs, double rhs) { return abs(lhs - m) < abs(rhs - m); }; - std::nth_element(first, first + n / 2, last, lessMedAbs); //complexity: O(n) - const double midVal = abs(*(first + n / 2) - m); + std::nth_element(first, first + n / 2, last, lessMedAbs); //complexity: O(n) + const double midVal = abs(*(first + n / 2) - m); - if (n % 2 != 0) - return midVal; - else //n is even and >= 2 in this context: return mean of two middle values - return 0.5 * (abs(*std::max_element(first, first + n / 2, lessMedAbs) - m) + midVal); - } - return 0; + if (n % 2 != 0) + return midVal; + else //n is even and >= 2 in this context: return mean of two middle values + return 0.5 * (abs(*std::max_element(first, first + n / 2, lessMedAbs) - m) + midVal); } diff --git a/zen/file_access.cpp b/zen/file_access.cpp index 69b6c388..e7467325 100755 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -14,8 +14,8 @@ #include "symlink_target.h" #include "file_id_def.h" #include "file_io.h" -#include "crc.h" -#include "guid.h" +#include "crc.h" //boost dependency! +#include "guid.h" // #include <sys/vfs.h> //statfs #include <sys/time.h> //lutimes @@ -627,10 +627,13 @@ FileCopyResult copyFileOsSpecific(const Zstring& sourceFile, //throw FileError, //=> don't delete file that existed previously!!! FileOutput fileOut(fdTarget, targetFile, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //pass ownership - bufferedStreamCopy(fileIn, fileOut); //throw FileError, X + //fileOut.preAllocateSpaceBestEffort(sourceInfo.st_size); //throw FileError + //=> perf: seems like no real benefit... + + bufferedStreamCopy(fileIn, fileOut); //throw FileError, (ErrorFileLocked), X //flush intermediate buffers before fiddling with the raw file handle - fileOut.flushBuffers(); //throw FileError, X + fileOut.flushBuffers(); //throw FileError, X struct ::stat targetInfo = {}; if (::fstat(fileOut.getHandle(), &targetInfo) != 0) diff --git a/zen/file_io.cpp b/zen/file_io.cpp index 60023849..68b41bcb 100755 --- a/zen/file_io.cpp +++ b/zen/file_io.cpp @@ -103,7 +103,7 @@ FileInput::FileInput(const Zstring& filePath, const IOCallback& notifyUnbuffered } -size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError; may return short, only 0 means EOF! +size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError, ErrorFileLocked; may return short, only 0 means EOF! { if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check! throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); @@ -127,7 +127,7 @@ size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError; m } -size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError, X; return "bytesToRead" bytes unless end of stream! +size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream! { const size_t blockSize = getBlockSize(); assert(memBuf_.size() <= blockSize); @@ -144,7 +144,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError, X; r break; //-------------------------------------------------------------------- memBuf_.resize(blockSize); - const size_t bytesRead = tryRead(&memBuf_[0], blockSize); //throw FileError; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0 + const size_t bytesRead = tryRead(&memBuf_[0], blockSize); //throw FileError, ErrorFileLocked; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0 memBuf_.resize(bytesRead); if (notifyUnbufferedIO_) notifyUnbufferedIO_(bytesRead); //throw X diff --git a/zen/file_io.h b/zen/file_io.h index 6b0665a1..c2071500 100755 --- a/zen/file_io.h +++ b/zen/file_io.h @@ -33,6 +33,7 @@ public: //Windows: use 64kB ?? https://technet.microsoft.com/en-us/library/cc938632 //Linux: use st_blksize? + //macOS: use f_iosize? static size_t getBlockSize() { return 128 * 1024; }; protected: @@ -58,10 +59,10 @@ public: FileInput(const Zstring& filePath, const IOCallback& notifyUnbufferedIO); //throw FileError, ErrorFileLocked FileInput(FileHandle handle, const Zstring& filePath, const IOCallback& notifyUnbufferedIO); //takes ownership! - size_t read(void* buffer, size_t bytesToRead); //throw FileError, X; return "bytesToRead" bytes unless end of stream! + size_t read(void* buffer, size_t bytesToRead); //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream! private: - size_t tryRead(void* buffer, size_t bytesToRead); //throw FileError; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0! + size_t tryRead(void* buffer, size_t bytesToRead); //throw FileError, ErrorFileLocked; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0! std::vector<char> memBuf_; const IOCallback notifyUnbufferedIO_; //throw X @@ -16,8 +16,8 @@ //minimal layer enabling text translation - without platform/library dependencies! #define ZEN_TRANS_CONCAT_SUB(X, Y) X ## Y -#define _(s) zen::implementation::translate(ZEN_TRANS_CONCAT_SUB(L, s)) -#define _P(s, p, n) zen::implementation::translate(ZEN_TRANS_CONCAT_SUB(L, s), ZEN_TRANS_CONCAT_SUB(L, p), n) +#define _(s) zen::translate(ZEN_TRANS_CONCAT_SUB(L, s)) +#define _P(s, p, n) zen::translate(ZEN_TRANS_CONCAT_SUB(L, s), ZEN_TRANS_CONCAT_SUB(L, p), n) //source and translation are required to use %x as number placeholder //for plural form, which will be substituted automatically!!! @@ -58,61 +58,55 @@ std::shared_ptr<const TranslationHandler> getTranslator(); namespace implementation { inline -std::wstring translate(const std::wstring& text) +Global<const TranslationHandler>& refGlobalTranslationHandler() { - if (std::shared_ptr<const TranslationHandler> t = getTranslator()) //std::shared_ptr => temporarily take (shared) ownership while using the interface! - return t->translate(text); - return text; + //getTranslator() may be called even after static objects of this translation unit are destroyed! + static Global<const TranslationHandler> inst; //external linkage even in header! + return inst; +} } - -//translate plural forms: "%x day" "%x days" -//returns "1 day" if n == 1; "123 days" if n == 123 for english language inline -std::wstring translate(const std::wstring& singular, const std::wstring& plural, int64_t n) +std::shared_ptr<const TranslationHandler> getTranslator() { - assert(contains(plural, L"%x")); - - if (std::shared_ptr<const TranslationHandler> t = getTranslator()) - { - std::wstring translation = t->translate(singular, plural, n); - assert(!contains(translation, L"%x")); - return translation; - } - - return replaceCpy(std::abs(n) == 1 ? singular : plural, L"%x", toGuiString(n)); + return implementation::refGlobalTranslationHandler().get(); } -template <class T> inline -std::wstring translate(const std::wstring& singular, const std::wstring& plural, T n) +inline +void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler) { - static_assert(sizeof(n) <= sizeof(int64_t), ""); - return translate(singular, plural, static_cast<int64_t>(n)); + implementation::refGlobalTranslationHandler().set(std::move(newHandler)); } inline -Global<const TranslationHandler>& refGlobalTranslationHandler() +std::wstring translate(const std::wstring& text) { - //getTranslator() may be called even after static objects of this translation unit are destroyed! - static Global<const TranslationHandler> inst; //external linkage even in header! - return inst; -} + if (std::shared_ptr<const TranslationHandler> t = getTranslator()) //std::shared_ptr => temporarily take (shared) ownership while using the interface! + return t->translate(text); + return text; } -inline -void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler) +//translate plural forms: "%x day" "%x days" +//returns "1 day" if n == 1; "123 days" if n == 123 for english language +template <class T> inline +std::wstring translate(const std::wstring& singular, const std::wstring& plural, T n) { - implementation::refGlobalTranslationHandler().set(std::move(newHandler)); -} + static_assert(sizeof(n) <= sizeof(int64_t), ""); + const auto n64 = static_cast<int64_t>(n); + assert(contains(plural, L"%x")); -inline -std::shared_ptr<const TranslationHandler> getTranslator() -{ - return implementation::refGlobalTranslationHandler().get(); + if (std::shared_ptr<const TranslationHandler> t = getTranslator()) + { + std::wstring translation = t->translate(singular, plural, n64); + assert(!contains(translation, L"%x")); + return translation; + } + //fallback: + return replaceCpy(std::abs(n64) == 1 ? singular : plural, L"%x", toGuiString(n)); } } diff --git a/zen/scope_guard.h b/zen/scope_guard.h index f4ffc92b..ccc6db0c 100755 --- a/zen/scope_guard.h +++ b/zen/scope_guard.h @@ -13,7 +13,7 @@ //std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP - static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support"); + static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 2 || (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support"); namespace __cxxabiv1 { diff --git a/zen/stl_tools.h b/zen/stl_tools.h index b03d7533..2fcecd11 100755 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -39,9 +39,6 @@ void append(std::set<T, LessType, Alloc>& s, const C& c); template <class KeyType, class ValueType, class LessType, class Alloc, class C> void append(std::map<KeyType, ValueType, LessType, Alloc>& m, const C& c); -template <class M, class K, class V> -V& map_add_or_update(M& map, const K& key, const V& value); //efficient add or update without "default-constructible" requirement (Effective STL, item 24) - template <class T, class Alloc> void removeDuplicates(std::vector<T, Alloc>& v); @@ -125,20 +122,6 @@ template <class KeyType, class ValueType, class LessType, class Alloc, class C> void append(std::map<KeyType, ValueType, LessType, Alloc>& m, const C& c) { m.insert(c.begin(), c.end()); } -template <class M, class K, class V> inline -V& map_add_or_update(M& map, const K& key, const V& value) //efficient add or update without "default-constructible" requirement (Effective STL, item 24) -{ - auto it = map.lower_bound(key); - if (it != map.end() && !(map.key_comp()(key, it->first))) - { - it->second = value; - return it->second; - } - else - return map.insert(it, typename M::value_type(key, value))->second; -} - - template <class T, class Alloc> inline void removeDuplicates(std::vector<T, Alloc>& v) { diff --git a/zen/string_tools.h b/zen/string_tools.h index bfa14257..0a24ab2a 100755 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -22,10 +22,11 @@ //enhance arbitray string class with useful non-member functions: namespace zen { -template <class Char> bool isWhiteSpace(Char ch); -template <class Char> bool isDigit (Char ch); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only! -template <class Char> bool isHexDigit (Char ch); -template <class Char> bool isAsciiAlpha(Char ch); +template <class Char> bool isWhiteSpace(Char c); +template <class Char> bool isDigit (Char c); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only! +template <class Char> bool isHexDigit (Char c); +template <class Char> bool isAsciiAlpha(Char c); +template <class Char> Char asciiToLower(Char c); //case-sensitive comparison (compile-time correctness: use different number of arguments as STL comparison predicates!) struct CmpBinary { template <class Char> int operator()(const Char* lhs, size_t lhsLen, const Char* rhs, size_t rhsLen) const; }; @@ -105,28 +106,28 @@ template <class T, class S> T copyStringTo(S&& str); //---------------------- implementation ---------------------- template <> inline -bool isWhiteSpace(char ch) +bool isWhiteSpace(char c) { - assert(ch != 0); //std C++ does not consider 0 as white space + assert(c != 0); //std C++ does not consider 0 as white space //caveat 1: std::isspace() takes an int, but expects an unsigned char //caveat 2: some parts of UTF-8 chars are erroneously seen as whitespace, e.g. the a0 from "\xec\x8b\xa0" (MSVC) - return static_cast<unsigned char>(ch) < 128 && - std::isspace(static_cast<unsigned char>(ch)) != 0; + return static_cast<unsigned char>(c) < 128 && + std::isspace(static_cast<unsigned char>(c)) != 0; } template <> inline -bool isWhiteSpace(wchar_t ch) +bool isWhiteSpace(wchar_t c) { - assert(ch != 0); //std C++ does not consider 0 as white space - return std::iswspace(ch) != 0; + assert(c != 0); //std C++ does not consider 0 as white space + return std::iswspace(c) != 0; } template <class Char> inline -bool isDigit(Char ch) //similar to implmenetation of std::isdigit()! +bool isDigit(Char c) //similar to implmenetation of std::isdigit()! { static_assert(IsSameType<Char, char>::value || IsSameType<Char, wchar_t>::value, ""); - return static_cast<Char>('0') <= ch && ch <= static_cast<Char>('9'); + return static_cast<Char>('0') <= c && c <= static_cast<Char>('9'); } @@ -149,6 +150,15 @@ bool isAsciiAlpha(Char c) } +template <class Char> inline +Char asciiToLower(Char c) +{ + if (static_cast<Char>('A') <= c && c <= static_cast<Char>('Z')) + return static_cast<Char>(c - static_cast<Char>('A') + static_cast<Char>('a')); + return c; +} + + template <class S, class T, class Function> inline bool startsWith(const S& str, const T& prefix, Function cmpStringFun) { @@ -458,19 +468,11 @@ int CmpBinary::operator()(const Char* lhs, size_t lhsLen, const Char* rhs, size_ template <class Char> inline int CmpAsciiNoCase::operator()(const Char* lhs, size_t lhsLen, const Char* rhs, size_t rhsLen) const { - auto asciiToLower = [](Char c) //ordering: lower-case chars have higher code points than uppper-case - { - if (static_cast<Char>('A') <= c && c <= static_cast<Char>('Z')) - return static_cast<Char>(c - static_cast<Char>('A') + static_cast<Char>('a')); - return c; - }; - const auto* const lhsLast = lhs + std::min(lhsLen, rhsLen); - while (lhs != lhsLast) { - const Char charL = asciiToLower(*lhs++); - const Char charR = asciiToLower(*rhs++); + const Char charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case + const Char charR = asciiToLower(*rhs++); // if (charL != charR) return static_cast<unsigned int>(charL) - static_cast<unsigned int>(charR); //unsigned char-comparison is the convention! //unsigned underflow is well-defined! @@ -23,12 +23,19 @@ struct TimeComp //replaces std::tm and SYSTEMTIME int second = 0; //0-60 (including leap second) }; +inline bool operator==(const TimeComp& lhs, const TimeComp& rhs) +{ + return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second; +} + TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components time_t utcToTimeT(const TimeComp& comp); //convert UTC time components to time_t (UTC), returns -1 on error +TimeComp getCompileTime(); + //---------------------------------------------------------------------------------------------------------------------------------- /* @@ -268,6 +275,23 @@ time_t utcToTimeT(const TimeComp& comp) //returns -1 on error } +inline +TimeComp getCompileTime() +{ + //https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html + char compileTime[] = __DATE__ " " __TIME__; //e.g. "Aug 1 2017 01:32:26" + if (compileTime[4] == ' ') //day is space-padded, but %d expects zero-padding + compileTime[4] = '0'; + + TimeComp tc = {}; + if (parseTime("%b %d %Y %H:%M:%S", compileTime, tc)) + return tc; + + assert(false); + return TimeComp(); +} + + template <class String, class String2> inline String formatTime(const String2& format, const TimeComp& comp) { @@ -328,6 +352,25 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur if (!extractNumber(comp.month, 2)) return false; break; + case 'b': //abbreviated month name: Jan-Dec + { + if (strLast - itStr < 3) + return false; + + const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; + auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name) + { + return asciiToLower(itStr[0]) == name[0] && + asciiToLower(itStr[1]) == name[1] && + asciiToLower(itStr[2]) == name[2]; + }); + if (itMonth == std::end(months)) + return false; + + comp.month = 1 + static_cast<int>(itMonth - std::begin(months)); + itStr += 3; + } + break; case 'd': if (!extractNumber(comp.day, 2)) return false; diff --git a/zen/xml_io.cpp b/zen/xml_io.cpp index 0a1c8505..8192d6e6 100755 --- a/zen/xml_io.cpp +++ b/zen/xml_io.cpp @@ -22,7 +22,7 @@ XmlDoc zen::loadXmlDocument(const Zstring& filePath) //throw FileError for (;;) { buffer.resize(buffer.size() + blockSize); - const size_t bytesRead = fileIn.read(&*(buffer.end() - blockSize), blockSize); //throw FileError, (X); return "bytesToRead" bytes unless end of stream! + const size_t bytesRead = fileIn.read(&*(buffer.end() - blockSize), blockSize); //throw FileError, ErrorFileLocked, (X); return "bytesToRead" bytes unless end of stream! buffer.resize(buffer.size() - blockSize + bytesRead); //caveat: unsigned arithmetics //quick test whether input is an XML: avoid loading large binary files up front! |