diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:17:51 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:17:51 +0200 |
commit | 237aedc590b58c0e69d7dfcac92b5f767b7c004a (patch) | |
tree | 83f361a82ba483f2daf83b677e8685cd953812d9 /lib | |
parent | 4.5 (diff) | |
download | FreeFileSync-237aedc590b58c0e69d7dfcac92b5f767b7c004a.tar.gz FreeFileSync-237aedc590b58c0e69d7dfcac92b5f767b7c004a.tar.bz2 FreeFileSync-237aedc590b58c0e69d7dfcac92b5f767b7c004a.zip |
4.6
Diffstat (limited to 'lib')
-rw-r--r-- | lib/custom_grid.cpp | 27 | ||||
-rw-r--r-- | lib/db_file.cpp | 8 | ||||
-rw-r--r-- | lib/dir_lock.cpp | 6 | ||||
-rw-r--r-- | lib/dir_name.cpp | 174 | ||||
-rw-r--r-- | lib/dir_name.h | 51 | ||||
-rw-r--r-- | lib/folder_history_box.cpp | 141 | ||||
-rw-r--r-- | lib/folder_history_box.h | 106 | ||||
-rw-r--r-- | lib/localization.cpp | 18 | ||||
-rw-r--r-- | lib/parallel_scan.cpp | 2 | ||||
-rw-r--r-- | lib/parse_plural.h | 2 | ||||
-rw-r--r-- | lib/process_xml.cpp | 110 | ||||
-rw-r--r-- | lib/process_xml.h | 32 | ||||
-rw-r--r-- | lib/statistics.cpp | 15 | ||||
-rw-r--r-- | lib/statistics.h | 12 | ||||
-rw-r--r-- | lib/status_handler.h | 10 |
15 files changed, 137 insertions, 577 deletions
diff --git a/lib/custom_grid.cpp b/lib/custom_grid.cpp index 736bc49d..92f3b718 100644 --- a/lib/custom_grid.cpp +++ b/lib/custom_grid.cpp @@ -1080,20 +1080,23 @@ void CustomGridRim::updateGridSizes() CustomGrid::updateGridSizes(); //set row label size + if (GetRowLabelSize() > 0) + { + //SetRowLabelSize(wxGRID_AUTOSIZE); -> we can do better + wxClientDC dc(GetGridRowLabelWindow()); + dc.SetFont(GetLabelFont()); - //SetRowLabelSize(wxGRID_AUTOSIZE); -> we can do better - wxClientDC dc(GetGridRowLabelWindow()); - dc.SetFont(GetLabelFont()); + wxArrayString lines; + lines.push_back(GetRowLabelValue(GetNumberRows())); - wxArrayString lines; - lines.push_back(GetRowLabelValue(GetNumberRows())); + long width = 0; + long dummy = 0; + GetTextBoxSize(dc, lines, &width, &dummy); - long width = 0; - long dummy = 0; - GetTextBoxSize(dc, lines, &width, &dummy); + width += 8; - width += 8; - SetRowLabelSize(width); + SetRowLabelSize(width); + } } @@ -1377,7 +1380,7 @@ void CustomGridRim::setTooltip(const wxMouseEvent& event) virtual void visit(const FileMapping& fileObj) { tipMsg_ = copyStringTo<wxString>(std::wstring() + fileObj.getRelativeName<side>() + L"\n" + - _("Size") + L": " + zen::filesizeToShortString(fileObj.getFileSize<side>()) + L"\n" + + _("Size") + L": " + zen::filesizeToShortString(to<Int64>(fileObj.getFileSize<side>())) + L"\n" + _("Date") + L": " + zen::utcToLocalTimeString(fileObj.getLastWriteTime<side>())); } @@ -1449,7 +1452,7 @@ xmlAccess::ColumnAttributes CustomGridRim::getDefaultColumnAttributes() newEntry.type = xmlAccess::SIZE; newEntry.position = 4; - newEntry.width = 70; + newEntry.width = 80; defaultColumnSettings.push_back(newEntry); newEntry.type = xmlAccess::DATE; diff --git a/lib/db_file.cpp b/lib/db_file.cpp index 60a721b1..51333687 100644 --- a/lib/db_file.cpp +++ b/lib/db_file.cpp @@ -37,9 +37,9 @@ typedef Zbase<char> MemoryStream; //ref-counted byte strea typedef std::map<UniqueId, MemoryStream> StreamMapping; //list of streams ordered by session UUID -//------------------------------------------------------------------------------------ -//| ensure 32/64 bit portability: used fixed size data types only e.g. std::uint32_t | -//------------------------------------------------------------------------------------ +//----------------------------------------------------------------------------------- +//| ensure 32/64 bit portability: use fixed size data types only e.g. std::uint32_t | +//----------------------------------------------------------------------------------- template <SelectedSide side> inline @@ -48,7 +48,7 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false) //Linux and Windows builds are binary incompatible: different file id?, problem with case sensitivity? //however 32 and 64 bit db files *are* designed to be binary compatible! //Give db files different names. - //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories + //make sure they end with ".ffs_db". These files will not be included into comparison #ifdef FFS_WIN Zstring dbname = Zstring(Zstr("sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING; #elif defined FFS_LINUX diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index ab3c84ea..9ca76310 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -447,10 +447,6 @@ bool tryLock(const Zstring& lockfilename) //throw FileError NULL); if (fileHandle == INVALID_HANDLE_VALUE) { -#ifndef _MSC_VER -#warning fix this problem! - //read-only FTP may return: ERROR_FILE_EXISTS (NetDrive @ GNU) -#endif if (::GetLastError() == ERROR_FILE_EXISTS) return false; else @@ -545,7 +541,7 @@ public: return activeLock; } } - catch (...) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock file + catch (FileError&) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock file //not yet in buffer, so create a new directory lock std::shared_ptr<SharedDirLock> newLock(new SharedDirLock(lockfilename, callback)); //throw FileError diff --git a/lib/dir_name.cpp b/lib/dir_name.cpp deleted file mode 100644 index 55a4185c..00000000 --- a/lib/dir_name.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "dir_name.h" -#include <wx/dnd.h> -#include <wx/window.h> -#include <wx/textctrl.h> -#include <wx/statbox.h> -#include <zen/thread.h> -#include <zen/file_handling.h> -#include "resolve_path.h" -#include <wx+/string_conv.h> -#include "folder_history_box.h" - -using namespace zen; - - -namespace -{ -void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, wxWindow& tooltipWnd, wxStaticBoxSizer* staticBox, size_t timeout) -{ - const wxString dirFormatted = toWx(getFormattedDirectoryName(toZ(dirname))); - - tooltipWnd.SetToolTip(dirFormatted); //wxComboBox bug: the edit control is not updated... http://trac.wxwidgets.org/ticket/12659 - - if (staticBox) - { - //change static box label only if there is a real difference to what is shown in wxTextCtrl anyway - wxString dirNormalized = dirname; - trim(dirNormalized); - if (!dirNormalized.empty() && !endsWith(dirNormalized, FILE_NAME_SEPARATOR)) - dirNormalized += FILE_NAME_SEPARATOR; - - staticBox->GetStaticBox()->SetLabel(dirNormalized == dirFormatted ? wxString(_("Drag && drop")) : dirFormatted); - } - - if (dirPicker && !dirFormatted.empty()) - { - Zstring dir = toZ(dirFormatted); //convert to Zstring first: we don't want to pass wxString by value and risk MT issues! - auto ft = async([=] { return zen::dirExists(dir); }); - - if (ft.timed_wait(boost::posix_time::milliseconds(timeout)) && ft.get()) //potentially slow network access: wait 200ms at most - dirPicker->SetPath(dirFormatted); - } -} - - -void setDirectoryName(const wxString& dirname, - wxTextCtrl* txtCtrl, - wxDirPickerCtrl* dirPicker, - wxWindow& tooltipWnd, - wxStaticBoxSizer* staticBox, - size_t timeout = 200) //pointers are optional -{ - if (txtCtrl) - txtCtrl->ChangeValue(dirname); - setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, staticBox, timeout); -} - - -void setDirectoryName(const wxString& dirname, - FolderHistoryBox* comboBox, - wxDirPickerCtrl* dirPicker, - wxWindow& tooltipWnd, - wxStaticBoxSizer* staticBox, - size_t timeout = 200) //pointers are optional -{ - if (comboBox) - comboBox->setValue(dirname); - setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, staticBox, timeout); -} -} -//############################################################################################################## - -template <class NameControl> -DirectoryName<NameControl>::DirectoryName(wxWindow& dropWindow, - wxDirPickerCtrl& dirPicker, - NameControl& dirName, - wxStaticBoxSizer* staticBox, - wxWindow* dropWindow2) : - dropWindow_(dropWindow), - dropWindow2_(dropWindow2), - dirPicker_(dirPicker), - dirName_(dirName), - staticBox_(staticBox) -{ - //prepare drag & drop - setupFileDrop(dropWindow); - if (dropWindow2) - setupFileDrop(*dropWindow2); - - //redirect drag & drop event back to this class - dropWindow.Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); - if (dropWindow2) - dropWindow2->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); - - //keep dirPicker and dirName synchronous - dirName_ .Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually), NULL, this); - dirPicker_.Connect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryName::OnDirSelected ), NULL, this); -} - - -template <class NameControl> -DirectoryName<NameControl>::~DirectoryName() -{ - dirName_ .Disconnect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually), NULL, this); - dirPicker_.Disconnect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryName::OnDirSelected ), NULL, this); -} - - -template <class NameControl> -void DirectoryName<NameControl>::OnFilesDropped(FFSFileDropEvent& event) -{ - if (event.getFiles().empty()) - return; - - if (acceptDrop(event.getFiles())) - { - const wxString fileName = event.getFiles()[0]; - if (dirExists(toZ(fileName))) - setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); - else - { - wxString parentName = beforeLast(fileName, utf8CvrtTo<wxString>(FILE_NAME_SEPARATOR)); //returns empty string if ch not found -#ifdef FFS_WIN - if (endsWith(parentName, L":")) //volume name - parentName += FILE_NAME_SEPARATOR; -#endif - if (dirExists(toZ(parentName))) - setDirectoryName(parentName, &dirName_, &dirPicker_, dirName_, staticBox_); - else //set original name unconditionally: usecase: inactive mapped network shares - setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); - } - } -} - - -template <class NameControl> -void DirectoryName<NameControl>::OnWriteDirManually(wxCommandEvent& event) -{ - setDirectoryName(event.GetString(), static_cast<NameControl*>(NULL), &dirPicker_, dirName_, staticBox_, 100); //potentially slow network access: wait 100 ms at most - event.Skip(); -} - - -template <class NameControl> -void DirectoryName<NameControl>::OnDirSelected(wxFileDirPickerEvent& event) -{ - const wxString newPath = event.GetPath(); - setDirectoryName(newPath, &dirName_, NULL, dirName_, staticBox_); - event.Skip(); -} - - -template <class NameControl> -wxString DirectoryName<NameControl>::getName() const -{ - return dirName_.GetValue(); -} - - -template <class NameControl> -void DirectoryName<NameControl>::setName(const wxString& dirname) -{ - setDirectoryName(dirname, &dirName_, &dirPicker_, dirName_, staticBox_); -} - - -//explicit template instantiations -template class DirectoryName<wxTextCtrl>; -template class DirectoryName<FolderHistoryBox>; diff --git a/lib/dir_name.h b/lib/dir_name.h deleted file mode 100644 index 43f2015d..00000000 --- a/lib/dir_name.h +++ /dev/null @@ -1,51 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef DRAGANDDROP_H_INCLUDED -#define DRAGANDDROP_H_INCLUDED - -#include <vector> -#include <wx/event.h> -#include <wx/sizer.h> -#include <wx/filepicker.h> -#include <wx+/file_drop.h> - -namespace zen -{ -//handle drag and drop, tooltip, label and manual input, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl - -template <class NameControl> //NameControl may be wxTextCtrl, FolderHistoryBox -class DirectoryName: private wxEvtHandler -{ -public: - DirectoryName(wxWindow& dropWindow, - wxDirPickerCtrl& dirPicker, - NameControl& dirName, - wxStaticBoxSizer* staticBox = NULL, - wxWindow* dropWindow2 = NULL); //optional - - ~DirectoryName(); - - wxString getName() const; - void setName(const wxString& dirname); - -private: - virtual bool acceptDrop(const std::vector<wxString>& droppedFiles) { return true; }; //return true if drop should be processed - - void OnFilesDropped(FFSFileDropEvent& event); - void OnWriteDirManually(wxCommandEvent& event); - void OnDirSelected(wxFileDirPickerEvent& event); - - const wxWindow& dropWindow_; - const wxWindow* dropWindow2_; - wxDirPickerCtrl& dirPicker_; - NameControl& dirName_; - wxStaticBoxSizer* staticBox_; //optional -}; -} - - -#endif // DRAGANDDROP_H_INCLUDED diff --git a/lib/folder_history_box.cpp b/lib/folder_history_box.cpp deleted file mode 100644 index c8bd042a..00000000 --- a/lib/folder_history_box.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "folder_history_box.h" -#include <list> -#include "resolve_path.h" - -using namespace zen; - - -FolderHistoryBox::FolderHistoryBox(wxWindow* parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - int n, - const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) : - wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) -#if wxCHECK_VERSION(2, 9, 1) - , dropDownShown(false) -#endif -{ - //##################################### - /*##*/ SetMinSize(wxSize(150, -1)); //## workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox - //##################################### - - //register key event to enable item deletion - Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(FolderHistoryBox::OnKeyEvent), NULL, this); - - //refresh history list on mouse click - Connect(wxEVT_LEFT_DOWN, wxEventHandler(FolderHistoryBox::OnUpdateList), NULL, this); - - Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(FolderHistoryBox::OnSelection), NULL, this); - -#if wxCHECK_VERSION(2, 9, 1) - Connect(wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEventHandler(FolderHistoryBox::OnShowDropDown), NULL, this); - Connect(wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEventHandler(FolderHistoryBox::OnHideDropDown), NULL, this); -#endif -} - - -#if wxCHECK_VERSION(2, 9, 1) -void FolderHistoryBox::OnShowDropDown(wxCommandEvent& event) -{ - dropDownShown = true; - event.Skip(); -} - - -void FolderHistoryBox::OnHideDropDown(wxCommandEvent& event) -{ - dropDownShown = false; - event.Skip(); -} -#endif - -//set value and update list are technically entangled: see potential bug description below -void FolderHistoryBox::setValueAndUpdateList(const wxString& dirname) -{ - //it may be a little lame to update the list on each mouse-button click, but it should be working and we dont't have to manipulate wxComboBox internals - - std::list<Zstring> dirList; - - //add some aliases to allow user changing to volume name and back, if possible -#ifdef FFS_WIN - std::vector<Zstring> aliases = getDirectoryAliases(toZ(dirname)); - dirList.insert(dirList.end(), aliases.begin(), aliases.end()); -#endif - - if (sharedHistory_.get()) - { - auto tmp = sharedHistory_->getList(); - //std::sort(tmp.begin(), tmp.end(), LessFilename()); - - if (!dirList.empty() && !tmp.empty()) - dirList.push_back(FolderHistory::lineSeparator()); - - dirList.insert(dirList.end(), tmp.begin(), tmp.end()); - } - //########################################################################################### - - //attention: if the target value is not part of the dropdown list, SetValue() will look for a string that *starts with* this value: - //e.g. if the dropdown list contains "222" SetValue("22") will erroneously set and select "222" instead, while "111" would be set correctly! - // -> by design on Windows! - if (std::find(dirList.begin(), dirList.end(), toZ(dirname)) == dirList.end()) - dirList.push_front(toZ(dirname)); - - Clear(); - std::for_each(dirList.begin(), dirList.end(), [&](const Zstring& dir) { this->Append(toWx(dir)); }); - //this->SetSelection(wxNOT_FOUND); //don't select anything - this->SetValue(dirname); //preserve main text! -} - - -void FolderHistoryBox::OnSelection(wxCommandEvent& event) -{ - event.Skip(); -} - - -void FolderHistoryBox::OnKeyEvent(wxKeyEvent& event) -{ - const int keyCode = event.GetKeyCode(); - if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) - { - //try to delete the currently selected config history item - int pos = this->GetCurrentSelection(); - if (0 <= pos && pos < static_cast<int>(this->GetCount()) && -#if wxCHECK_VERSION(2, 9, 1) - dropDownShown) -#else - //what a mess...: - (GetValue() != GetString(pos) || //avoid problems when a character shall be deleted instead of list item - GetValue() == wxEmptyString)) //exception: always allow removing empty entry -#endif - { - //save old (selected) value: deletion seems to have influence on this - const wxString currentVal = this->GetValue(); - //this->SetSelection(wxNOT_FOUND); - - //delete selected row - if (sharedHistory_.get()) - sharedHistory_->delItem(toZ(GetString(pos))); - SetString(pos, wxString()); //in contrast to Delete(), this one does not kill the drop-down list and gives a nice visual feedback! - //Delete(pos); - - //(re-)set value - this->SetValue(currentVal); - - //eat up key event - return; - } - } - event.Skip(); -} diff --git a/lib/folder_history_box.h b/lib/folder_history_box.h deleted file mode 100644 index 859234cc..00000000 --- a/lib/folder_history_box.h +++ /dev/null @@ -1,106 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef CUSTOMCOMBOBOX_H_INCLUDED -#define CUSTOMCOMBOBOX_H_INCLUDED - -#include <wx/combobox.h> -#include <memory> -#include <zen/zstring.h> -#include <wx+/string_conv.h> -#include <zen/stl_tools.h> - -//combobox with history function + functionality to delete items (DEL) - - -class FolderHistory -{ -public: - FolderHistory() : maxSize_(0) {} - - FolderHistory(const std::vector<Zstring>& dirnames, size_t maxSize) : - maxSize_(maxSize), - dirnames_(dirnames) - { - if (dirnames_.size() > maxSize_) //keep maximal size of history list - dirnames_.resize(maxSize_); - } - - const std::vector<Zstring>& getList() const { return dirnames_; } - - static const Zstring lineSeparator() { return Zstr("---------------------------------------------------------------------------------------------------------------"); } - - void addItem(const Zstring& dirname) - { - if (dirname.empty() || dirname == lineSeparator()) - return; - - Zstring nameTmp = dirname; - zen::trim(nameTmp); - - //insert new folder or put it to the front if already existing - auto iter = std::find_if(dirnames_.begin(), dirnames_.end(), - [&](const Zstring& entry) { return ::EqualFilename()(entry, nameTmp); }); - - if (iter != dirnames_.end()) - dirnames_.erase(iter); - dirnames_.insert(dirnames_.begin(), nameTmp); - - if (dirnames_.size() > maxSize_) //keep maximal size of history list - dirnames_.resize(maxSize_); - } - - void delItem(const Zstring& dirname) { zen::vector_remove_if(dirnames_, [&](const Zstring& entry) { return ::EqualFilename()(entry, dirname); }); } - -private: - - size_t maxSize_; - std::vector<Zstring> dirnames_; -}; - - -class FolderHistoryBox : public wxComboBox -{ -public: - FolderHistoryBox(wxWindow* parent, - wxWindowID id, - const wxString& value = wxEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - int n = 0, - const wxString choices[] = NULL, - long style = 0, - const wxValidator& validator = wxDefaultValidator, - const wxString& name = wxComboBoxNameStr); - - void init(const std::shared_ptr<FolderHistory>& sharedHistory) { sharedHistory_ = sharedHistory; } - - void setValue(const wxString& dirname) - { - setValueAndUpdateList(dirname); //required for setting value correctly + Linux to ensure the dropdown is shown as being populated - } - - // GetValue - -private: - void OnKeyEvent(wxKeyEvent& event); - void OnSelection(wxCommandEvent& event); - void OnUpdateList(wxEvent& event) { setValueAndUpdateList(GetValue()); event.Skip(); } - - void setValueAndUpdateList(const wxString& dirname); - -#if wxCHECK_VERSION(2, 9, 1) - void OnShowDropDown(wxCommandEvent& event); - void OnHideDropDown(wxCommandEvent& event); - - bool dropDownShown; -#endif - - std::shared_ptr<FolderHistory> sharedHistory_; -}; - - -#endif // CUSTOMCOMBOBOX_H_INCLUDED diff --git a/lib/localization.cpp b/lib/localization.cpp index 574910ea..8084eb42 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -28,8 +28,6 @@ using namespace zen; namespace { //global objects -std::wstring THOUSANDS_SEPARATOR = L","; - class FFSLocale : public TranslationHandler { @@ -38,8 +36,6 @@ public: wxLanguage langId() const { return langId_; } - virtual std::wstring thousandsSeparator() { return THOUSANDS_SEPARATOR; }; - virtual std::wstring translate(const std::wstring& text) { //look for translation in buffer table @@ -352,23 +348,13 @@ public: const wxLanguageInfo* sysLngInfo = wxLocale::GetLanguageInfo(wxLocale::GetSystemLanguage()); const wxLanguageInfo* selLngInfo = wxLocale::GetLanguageInfo(selectedLng); - bool sysLangIsRTL = sysLngInfo ? sysLngInfo->LayoutDirection == wxLayout_RightToLeft : false; - bool selectedLangIsRTL = selLngInfo ? selLngInfo->LayoutDirection == wxLayout_RightToLeft : false; + const bool sysLangIsRTL = sysLngInfo ? sysLngInfo->LayoutDirection == wxLayout_RightToLeft : false; + const bool selectedLangIsRTL = selLngInfo ? selLngInfo->LayoutDirection == wxLayout_RightToLeft : false; if (sysLangIsRTL == selectedLangIsRTL) loc.Init(wxLANGUAGE_DEFAULT); //use sys-lang to preserve sub-language specific rules (e.g. german swiss number punctation) else loc.Init(selectedLng); - - //::setlocale (LC_ALL, ""); -> implicitly called by wxLocale - const lconv* localInfo = ::localeconv(); - - //actually these two parameters are language dependent, but we take system setting to handle all kinds of language derivations - THOUSANDS_SEPARATOR = utf8CvrtTo<wxString>(localInfo->thousands_sep); - - // why not working? - // THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).thousands_sep(); - // DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).decimal_point(); } private: wxLocale loc; //required for RTL language support (and nothing else) diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index 1052a408..a98623cf 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -345,7 +345,7 @@ void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const { boost::this_thread::interruption_point(); - const Zstring fileNameShort = shortName; + const Zstring fileNameShort(shortName); //do not list the database file(s) sync.ffs_db, sync.x64.ffs_db, etc. or lock files if (endsWith(fileNameShort, SYNC_DB_FILE_ENDING) || diff --git a/lib/parse_plural.h b/lib/parse_plural.h index 4ac9e47b..c4466320 100644 --- a/lib/parse_plural.h +++ b/lib/parse_plural.h @@ -212,7 +212,7 @@ private: private: bool startsWith(const Wstring& prefix) const { - if (stream.end() - pos < static_cast<int>(prefix.size())) + if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size())) return false; return std::equal(prefix.begin(), prefix.end(), pos); } diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp index 78e14ff5..ef324246 100644 --- a/lib/process_xml.cpp +++ b/lib/process_xml.cpp @@ -736,27 +736,24 @@ void readConfig(const XmlIn& in, FolderPairEnh& enhPair) void readConfig(const XmlIn& in, MainConfiguration& mainCfg) { //read compare settings - XmlIn inCmp = in["MainConfig"]["Comparison"]; + XmlIn inMain = in["MainConfig"]; - readConfig(inCmp, mainCfg.cmpConfig); + readConfig(inMain["Comparison"], mainCfg.cmpConfig); //########################################################### - XmlIn inSync = in["MainConfig"]["SyncConfig"]; - //read sync configuration - readConfig(inSync, mainCfg.syncCfg); + readConfig(inMain["SyncConfig"], mainCfg.syncCfg); //########################################################### - XmlIn inFilter = in["MainConfig"]["GlobalFilter"]; //read filter settings - readConfig(inFilter, mainCfg.globalFilter); + readConfig(inMain["GlobalFilter"], mainCfg.globalFilter); //########################################################### //read all folder pairs mainCfg.additionalPairs.clear(); bool firstIter = true; - for (XmlIn inPair = in["MainConfig"]["FolderPairs"]["Pair"]; inPair; inPair.next()) + for (XmlIn inPair = inMain["FolderPairs"]["Pair"]; inPair; inPair.next()) { FolderPairEnh newPair; readConfig(inPair, newPair); @@ -769,6 +766,8 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg) else mainCfg.additionalPairs.push_back(newPair); //set additional folder pairs } + + inMain["ExecuteWhenFinished"](mainCfg.onCompletion); } @@ -792,7 +791,16 @@ void readConfig(const XmlIn& in, xmlAccess::XmlBatchConfig& config) //read GUI specific config data XmlIn inBatchCfg = in["BatchConfig"]; - inBatchCfg["Silent" ](config.silent); + //----------------------------------------------------------------------------- + if (inBatchCfg["Silent"]) + { + inBatchCfg["Silent"](config.showProgress); + config.showProgress = !config.showProgress; + } + else + //----------------------------------------------------------------------------- + + inBatchCfg["ShowProgress" ](config.showProgress); inBatchCfg["LogfileDirectory"](config.logFileDirectory); inBatchCfg["LogfileCountMax" ](config.logFileCountMax); inBatchCfg["HandleError" ](config.handleError); @@ -828,14 +836,20 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) //gui specific global settings (optional) XmlIn inGui = in["Gui"]; - XmlIn inWnd = inGui["Windows"]["Main"]; + XmlIn inWnd = inGui["MainDialog"]; //read application window size and position - inWnd["Width" ](config.gui.dlgSize.x); - inWnd["Height" ](config.gui.dlgSize.y); - inWnd["PosX" ](config.gui.dlgPos.x); - inWnd["PosY" ](config.gui.dlgPos.y); - inWnd["Maximized"](config.gui.isMaximized); + inWnd.attribute("Width", config.gui.dlgSize.x); + inWnd.attribute("Height", config.gui.dlgSize.y); + inWnd.attribute("PosX", config.gui.dlgPos.x); + inWnd.attribute("PosY", config.gui.dlgPos.y); + inWnd.attribute("Maximized", config.gui.isMaximized); + + // inWnd["Width" ](config.gui.dlgSize.x); + // inWnd["Height" ](config.gui.dlgSize.y); + // inWnd["PosX" ](config.gui.dlgPos.x); + // inWnd["PosY" ](config.gui.dlgPos.y); + // inWnd["Maximized"](config.gui.isMaximized); inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible); @@ -862,11 +876,15 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) for (size_t i = 0; i < config.gui.columnAttribRight.size(); ++i) config.gui.columnAttribRight[i].position = i; - inWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft); - inWnd["FolderHistoryRight"](config.gui.folderHistoryRight); - inWnd["MaximumHistorySize"](config.gui.folderHistMax); inWnd["Perspective" ](config.gui.guiPerspectiveLast); + inGui["FolderHistoryLeft" ](config.gui.folderHistoryLeft); + inGui["FolderHistoryRight"](config.gui.folderHistoryRight); + inGui["FolderHistoryLeft"].attribute("MaxSize", config.gui.folderHistMax); + + inGui["OnCompletionHistory"](config.gui.onCompletionHistory); + inGui["OnCompletionHistory"].attribute("MaxSize", config.gui.onCompletionHistoryMax); + //external applications inGui["ExternalApplications"](config.gui.externelApplications); @@ -1002,24 +1020,26 @@ void writeConfigFolderPair(const FolderPairEnh& enhPair, XmlOut& out) void writeConfig(const MainConfiguration& mainCfg, XmlOut& out) { - XmlOut outCmp = out["MainConfig"]["Comparison"]; + XmlOut outMain = out["MainConfig"]; + + XmlOut outCmp = outMain["Comparison"]; writeConfig(mainCfg.cmpConfig, outCmp); //########################################################### - XmlOut outSync = out["MainConfig"]["SyncConfig"]; + XmlOut outSync = outMain["SyncConfig"]; writeConfig(mainCfg.syncCfg, outSync); //########################################################### - XmlOut outFilter = out["MainConfig"]["GlobalFilter"]; + XmlOut outFilter = outMain["GlobalFilter"]; //write filter settings writeConfig(mainCfg.globalFilter, outFilter); //########################################################### //write all folder pairs - XmlOut outFp = out["MainConfig"]["FolderPairs"]; + XmlOut outFp = outMain["FolderPairs"]; //write first folder pair writeConfigFolderPair(mainCfg.firstPair, outFp); @@ -1027,6 +1047,8 @@ void writeConfig(const MainConfiguration& mainCfg, XmlOut& out) //write additional folder pairs std::for_each(mainCfg.additionalPairs.begin(), mainCfg.additionalPairs.end(), [&](const FolderPairEnh& fp) { writeConfigFolderPair(fp, outFp); }); + + outMain["ExecuteWhenFinished"](mainCfg.onCompletion); } @@ -1050,7 +1072,7 @@ void writeConfig(const XmlBatchConfig& config, XmlOut& out) //write GUI specific config data XmlOut outBatchCfg = out["BatchConfig"]; - outBatchCfg["Silent" ](config.silent); + outBatchCfg["ShowProgress" ](config.showProgress); outBatchCfg["LogfileDirectory"](config.logFileDirectory); outBatchCfg["LogfileCountMax" ](config.logFileCountMax); outBatchCfg["HandleError" ](config.handleError); @@ -1077,23 +1099,23 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) outOpt["CheckForDependentFolders" ](config.optDialogs.warningDependentFolders); outOpt["CheckForMultipleWriteAccess" ](config.optDialogs.warningMultiFolderWriteAccess); outOpt["CheckForSignificantDifference"](config.optDialogs.warningSignificantDifference); - outOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace); - outOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts); - outOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase); - outOpt["CheckMissingRecycleBin"](config.optDialogs.warningRecyclerMissing); - outOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange); - outOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync); + outOpt["CheckForFreeDiskSpace" ](config.optDialogs.warningNotEnoughDiskSpace); + outOpt["CheckForUnresolvedConflicts" ](config.optDialogs.warningUnresolvedConflicts); + outOpt["NotifyDatabaseError" ](config.optDialogs.warningSyncDatabase); + outOpt["CheckMissingRecycleBin" ](config.optDialogs.warningRecyclerMissing); + outOpt["PopupOnConfigChange" ](config.optDialogs.popupOnConfigChange); + outOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync); //gui specific global settings (optional) XmlOut outGui = out["Gui"]; - XmlOut outWnd = outGui["Windows"]["Main"]; + XmlOut outWnd = outGui["MainDialog"]; //write application window size and position - outWnd["Width" ](config.gui.dlgSize.x); - outWnd["Height" ](config.gui.dlgSize.y); - outWnd["PosX" ](config.gui.dlgPos.x); - outWnd["PosY" ](config.gui.dlgPos.y); - outWnd["Maximized"](config.gui.isMaximized); + outWnd.attribute("Width", config.gui.dlgSize.x); + outWnd.attribute("Height", config.gui.dlgSize.y); + outWnd.attribute("PosX", config.gui.dlgPos.x); + outWnd.attribute("PosY", config.gui.dlgPos.y); + outWnd.attribute("Maximized", config.gui.isMaximized); outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible); @@ -1107,27 +1129,29 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) //write column attributes XmlOut outColLeft = outWnd["LeftColumns"]; - outColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft); - + outColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft); outColLeft(config.gui.columnAttribLeft); //########################################################### XmlOut outColRight = outWnd["RightColumns"]; - outColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight); - + outColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight); outColRight(config.gui.columnAttribRight); - outWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft); - outWnd["FolderHistoryRight"](config.gui.folderHistoryRight); - outWnd["MaximumHistorySize"](config.gui.folderHistMax); outWnd["Perspective" ](config.gui.guiPerspectiveLast); + outGui["FolderHistoryLeft" ](config.gui.folderHistoryLeft); + outGui["FolderHistoryRight"](config.gui.folderHistoryRight); + outGui["FolderHistoryLeft" ].attribute("MaxSize", config.gui.folderHistMax); + + outGui["OnCompletionHistory"](config.gui.onCompletionHistory); + outGui["OnCompletionHistory"].attribute("MaxSize", config.gui.onCompletionHistoryMax); + //external applications outGui["ExternalApplications"](config.gui.externelApplications); //load config file history outGui["LastConfigActive"](config.gui.lastUsedConfigFiles); - outGui["ConfigHistory"](config.gui.cfgFileHistory); + outGui["ConfigHistory" ](config.gui.cfgFileHistory); //last update check outGui["LastUpdateCheck"](config.gui.lastUpdateCheck); diff --git a/lib/process_xml.h b/lib/process_xml.h index 7f8b273b..d8ca7e54 100644 --- a/lib/process_xml.h +++ b/lib/process_xml.h @@ -93,13 +93,13 @@ struct XmlGuiConfig struct XmlBatchConfig { XmlBatchConfig() : - silent(false), + showProgress(true), logFileCountMax(200), handleError(ON_ERROR_POPUP) {} zen::MainConfiguration mainCfg; - bool silent; + bool showProgress; wxString logFileDirectory; size_t logFileCountMax; OnError handleError; //reaction on error situation during synchronization @@ -160,9 +160,9 @@ struct XmlGlobalSettings OptionalDialogs optDialogs; //--------------------------------------------------------------------- - struct _Gui + struct Gui { - _Gui() : + Gui() : dlgPos(wxDefaultCoord, wxDefaultCoord), dlgSize(wxDefaultCoord, wxDefaultCoord), isMaximized(false), @@ -170,6 +170,7 @@ struct XmlGlobalSettings autoAdjustColumnsLeft(false), autoAdjustColumnsRight(false), folderHistMax(15), + onCompletionHistoryMax(8), deleteOnBothSides(false), useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message #ifdef FFS_WIN @@ -180,17 +181,17 @@ struct XmlGlobalSettings iconSize(ICON_SIZE_SMALL), lastUpdateCheck(0) { - //default external apps will be translated "on the fly"!!! + //default external apps will be translated "on the fly"!!! First entry will be used for [Enter] or mouse double-click! #ifdef FFS_WIN - externelApplications.push_back(std::make_pair(wxT("Show in Explorer"), //mark for extraction: _("Show in Explorer") - wxT("explorer /select, \"%name\""))); - externelApplications.push_back(std::make_pair(wxT("Open with default application"), //mark for extraction: _("Open with default application") - wxT("\"%name\""))); + externelApplications.push_back(std::make_pair(L"Show in Explorer", //mark for extraction: _("Show in Explorer") + L"explorer /select, \"%name\"")); + externelApplications.push_back(std::make_pair(L"Open with default application", //mark for extraction: _("Open with default application") + L"\"%name\"")); #elif defined FFS_LINUX - externelApplications.push_back(std::make_pair(wxT("Browse directory"), //mark for extraction: _("Browse directory") - wxT("xdg-open \"%dir\""))); - externelApplications.push_back(std::make_pair(wxT("Open with default application"), //mark for extraction: _("Open with default application") - wxT("xdg-open \"%name\""))); + externelApplications.push_back(std::make_pair(L"Browse directory", //mark for extraction: _("Browse directory") + L"xdg-open \"%dir\"")); + externelApplications.push_back(std::make_pair(L"Open with default application", //mark for extraction: _("Open with default application") + L"xdg-open \"%name\"")); #endif } @@ -215,6 +216,9 @@ struct XmlGlobalSettings std::vector<Zstring> folderHistoryRight; unsigned int folderHistMax; + std::vector<std::wstring> onCompletionHistory; + size_t onCompletionHistoryMax; + bool deleteOnBothSides; bool useRecyclerForManualDeletion; bool textSearchRespectCase; @@ -227,7 +231,7 @@ struct XmlGlobalSettings } gui; //--------------------------------------------------------------------- - //struct _Batch + //struct Batch }; diff --git a/lib/statistics.cpp b/lib/statistics.cpp index 9924091c..6cc3c0cd 100644 --- a/lib/statistics.cpp +++ b/lib/statistics.cpp @@ -79,6 +79,13 @@ void Statistics::addMeasurement(int objectsCurrent, double dataCurrent) } +void Statistics::setNewTotal(int totalObjectCount, double totalDataAmount) +{ + objectsTotal = totalObjectCount; + dataTotal = totalDataAmount; +} + + wxString Statistics::getRemainingTime() const { if (!measurements.empty()) @@ -92,12 +99,14 @@ wxString Statistics::getRemainingTime() const const TimeRecordMap::value_type& frontRecord = *windowBegin; //----------------------------------------------------------------------------------------------- - const double timeDelta = backRecord.first - frontRecord.first; + const double timeDelta = backRecord.first - frontRecord.first; const double dataDelta = backRecord.second.data - frontRecord.second.data; const double dataRemaining = dataTotal - backRecord.second.data; + //objects do *NOT* correspond to disk accesses, so we better play safe and use "bytes" only! + //https://sourceforge.net/tracker/index.php?func=detail&aid=3452469&group_id=234430&atid=1093083 - if (!numeric::isNull(dataDelta)) + if (!numeric::isNull(dataDelta)) //sign(dataRemaining) != sign(dataDelta) usually an error, so show it! { int remTimeSec = dataRemaining * timeDelta / (1000.0 * dataDelta); return zen::remainingTimeToShortString(remTimeSec); @@ -126,7 +135,7 @@ wxString Statistics::getBytesPerSecond() const if (!numeric::isNull(timeDelta)) if (dataDelta > 0) //may be negative if user cancels copying - return zen::filesizeToShortString(zen::UInt64(dataDelta * 1000 / timeDelta)) + _("/sec"); + return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec"); } return wxT("-"); //fallback diff --git a/lib/statistics.h b/lib/statistics.h index 718e4f19..62a30b99 100644 --- a/lib/statistics.h +++ b/lib/statistics.h @@ -42,6 +42,8 @@ public: unsigned windowSizeBytesPerSecond); //time in ms void addMeasurement(int objectsCurrent, double dataCurrent); + void setNewTotal(int totalObjectCount, double totalDataAmount); //may change during sync! + wxString getRemainingTime() const; //returns the remaining time in milliseconds wxString getBytesPerSecond() const; @@ -49,12 +51,12 @@ public: void resumeTimer(); private: - const int objectsTotal; - const double dataTotal; + int objectsTotal; + double dataTotal; - const unsigned windowSizeRemTime; //"window width" of statistics used for calculation of remaining time in ms - const unsigned windowSizeBPS; // - const unsigned windowMax; + const unsigned int windowSizeRemTime; //"window width" of statistics used for calculation of remaining time in ms + const unsigned int windowSizeBPS; // + const unsigned int windowMax; struct Record { diff --git a/lib/status_handler.h b/lib/status_handler.h index 686c1f0e..acab956a 100644 --- a/lib/status_handler.h +++ b/lib/status_handler.h @@ -44,7 +44,15 @@ struct ProcessCallback //note: this one must NOT throw in order to properly allow undoing setting of statistics! //it is in general paired with a call to requestUiRefresh() to compensate! - virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw()!! + virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta) = 0; //throw()!! + virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta) = 0; // + /*the estimated total may change *during* sync: + 1. move file -> fallback to copy + delete + 2. file copy, actual size changed after comparison + 3. auto-resolution for failed create operations due to missing source + 4. directory deletion: may contain more items than scanned by FFS: excluded by filter + 5. delete directory to recycler or move to user-defined dir on same volume: no matter how many sub-elements exist, this is only 1 object to process! + 6. user-defined deletion directory on different volume: full file copy required (instead of move) */ //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() virtual void requestUiRefresh() = 0; //throw ? |