summaryrefslogtreecommitdiff
path: root/RealtimeSync
diff options
context:
space:
mode:
Diffstat (limited to 'RealtimeSync')
-rw-r--r--RealtimeSync/RealtimeSync.vcxproj26
-rw-r--r--RealtimeSync/application.cpp27
-rw-r--r--RealtimeSync/gui_generated.cpp6
-rw-r--r--RealtimeSync/gui_generated.h2
-rw-r--r--RealtimeSync/main_dlg.cpp88
-rw-r--r--RealtimeSync/main_dlg.h17
-rw-r--r--RealtimeSync/makefile2
-rw-r--r--RealtimeSync/monitor.cpp (renamed from RealtimeSync/watcher.cpp)187
-rw-r--r--RealtimeSync/monitor.h38
-rw-r--r--RealtimeSync/tray_menu.cpp440
-rw-r--r--RealtimeSync/tray_menu.h10
-rw-r--r--RealtimeSync/watcher.h54
-rw-r--r--RealtimeSync/xml_ffs.cpp14
-rw-r--r--RealtimeSync/xml_proc.h8
14 files changed, 493 insertions, 426 deletions
diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj
index 487f2cce..08abd76f 100644
--- a/RealtimeSync/RealtimeSync.vcxproj
+++ b/RealtimeSync/RealtimeSync.vcxproj
@@ -29,27 +29,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <PlatformToolset>v120_xp</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -99,7 +99,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;wxUSE_UNICODE;__WXMSW__;ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll\mswud;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc12_x86_debug_dll\mswud;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -114,7 +114,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxbase28ud.lib;wxpngd.lib;wxzlibd.lib;wxbase28ud_net.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc12_x86_debug_dll</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -127,7 +127,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;wxUSE_UNICODE;__WXMSW__;ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll\mswud;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc12_x64_debug_dll\mswud;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -144,7 +144,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxbase28ud.lib;wxpngd.lib;wxzlibd.lib;wxbase28ud_net.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc12_x64_debug_dll</AdditionalLibraryDirectories>
<LinkStatus>
</LinkStatus>
</Link>
@@ -160,7 +160,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;wxUSE_UNICODE;__WXMSW__;ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib\mswu;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc12_x86_release_lib\mswu;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -174,7 +174,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxbase28u.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc12_x86_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -191,7 +191,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;wxUSE_UNICODE;__WXMSW__;ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib\mswu;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc12_x64_release_lib\mswu;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -205,7 +205,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxmsw28u_adv.lib;wxmsw28u_core.lib;wxbase28u.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc12_x64_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -246,9 +246,9 @@
</ClCompile>
<ClCompile Include="gui_generated.cpp" />
<ClCompile Include="main_dlg.cpp" />
+ <ClCompile Include="monitor.cpp" />
<ClCompile Include="resources.cpp" />
<ClCompile Include="tray_menu.cpp" />
- <ClCompile Include="watcher.cpp" />
<ClCompile Include="xml_ffs.cpp" />
<ClCompile Include="xml_proc.cpp" />
</ItemGroup>
diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp
index a7aff305..af8a40a9 100644
--- a/RealtimeSync/application.cpp
+++ b/RealtimeSync/application.cpp
@@ -36,19 +36,20 @@ IMPLEMENT_APP(Application);
namespace
{
+/*
boost::thread::id mainThreadId = boost::this_thread::get_id();
void onTerminationRequested()
{
- std::wstring msg = boost::this_thread::get_id() == mainThreadId ?
- L"Termination requested in main thread!\n\n" :
- L"Termination requested in worker thread!\n\n";
- msg += L"Please file a bug report at: http://sourceforge.net/projects/freefilesync";
+std::wstring msg = boost::this_thread::get_id() == mainThreadId ?
+ L"Termination requested in main thread!\n\n" :
+ L"Termination requested in worker thread!\n\n";
+msg += L"Please file a bug report at: http://sourceforge.net/projects/freefilesync";
- wxSafeShowMessage(_("An exception occurred"), msg);
- std::abort();
+wxSafeShowMessage(_("An exception occurred"), msg);
+std::abort();
}
-
+*/
#ifdef _MSC_VER
void crtInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) { assert(false); }
#endif
@@ -59,7 +60,7 @@ const wxEventType EVENT_ENTER_EVENT_LOOP = wxNewEventType();
bool Application::OnInit()
{
- std::set_terminate(onTerminationRequested); //unlike wxWidgets uncaught exception handling, this works for all worker threads
+ //std::set_terminate(onTerminationRequested); //unlike wxWidgets uncaught exception handling, this works for all worker threads
#ifdef ZEN_WIN
#ifdef _MSC_VER
@@ -107,12 +108,12 @@ void Application::onEnterEventLoop(wxEvent& event)
}
catch (const FileError& e)
{
- wxMessageBox(e.toString(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(e.toString(), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR);
//continue!
}
//try to set config/batch-filename set by %1 parameter
- std::vector<wxString> commandArgs;
+ std::vector<Zstring> commandArgs;
for (int i = 1; i < argc; ++i)
{
Zstring filename = toZ(argv[i]);
@@ -125,14 +126,14 @@ void Application::onEnterEventLoop(wxEvent& event)
filename += Zstr(".ffs_batch");
else
{
- wxMessageBox(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR);
return;
}
}
- commandArgs.push_back(toWx(filename));
+ commandArgs.push_back(filename);
}
- wxString cfgFilename;
+ Zstring cfgFilename;
if (!commandArgs.empty())
cfgFilename = commandArgs[0];
diff --git a/RealtimeSync/gui_generated.cpp b/RealtimeSync/gui_generated.cpp
index cf072240..659f7ea4 100644
--- a/RealtimeSync/gui_generated.cpp
+++ b/RealtimeSync/gui_generated.cpp
@@ -100,6 +100,8 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
bSizer1->Add( m_staticText7, 0, wxALL, 5 );
m_panelMainFolder = new wxPanel( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_panelMainFolder->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
wxFlexGridSizer* fgSizer1;
fgSizer1 = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer1->AddGrowableCol( 1 );
@@ -152,6 +154,8 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_scrolledWinFolders = new wxScrolledWindow( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHSCROLL|wxVSCROLL );
m_scrolledWinFolders->SetScrollRate( 10, 10 );
+ m_scrolledWinFolders->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
bSizerFolders = new wxBoxSizer( wxVERTICAL );
@@ -243,6 +247,8 @@ MainDlgGenerated::~MainDlgGenerated()
FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style )
{
+ this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
+
wxBoxSizer* bSizer114;
bSizer114 = new wxBoxSizer( wxHORIZONTAL );
diff --git a/RealtimeSync/gui_generated.h b/RealtimeSync/gui_generated.h
index 2b42b271..aabb23fc 100644
--- a/RealtimeSync/gui_generated.h
+++ b/RealtimeSync/gui_generated.h
@@ -140,7 +140,7 @@ protected:
public:
- ErrorDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Error"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
+ ErrorDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Error"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~ErrorDlgGenerated();
};
diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp
index b750b110..b7a0aee1 100644
--- a/RealtimeSync/main_dlg.cpp
+++ b/RealtimeSync/main_dlg.cpp
@@ -9,8 +9,7 @@
#include <wx/msgdlg.h>
#include <wx/wupdlock.h>
#include <wx/filedlg.h>
-#include <wx/utils.h>
-#include <wx/filedlg.h>
+//#include <wx/utils.h>
#include <wx+/button.h>
#include <wx+/string_conv.h>
#include <wx+/mouse_move_dlg.h>
@@ -18,7 +17,6 @@
#include <zen/assert_static.h>
#include <zen/file_handling.h>
#include <zen/build_info.h>
-#include "watcher.h"
#include "xml_proc.h"
#include "tray_menu.h"
#include "xml_ffs.h"
@@ -44,7 +42,7 @@ private:
};
-MainDialog::MainDialog(wxDialog* dlg, const wxString& cfgFileName)
+MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
: MainDlgGenerated(dlg)
{
#ifdef ZEN_WIN
@@ -73,20 +71,20 @@ MainDialog::MainDialog(wxDialog* dlg, const wxString& cfgFileName)
//--------------------------- load config values ------------------------------------
xmlAccess::XmlRealConfig newConfig;
- const wxString currentConfigFile = cfgFileName.empty() ? lastConfigFileName() : cfgFileName;
+ const Zstring currentConfigFile = cfgFileName.empty() ? lastConfigFileName() : cfgFileName;
bool loadCfgSuccess = false;
- if (!cfgFileName.empty() || wxFileExists(lastConfigFileName()))
+ if (!cfgFileName.empty() || fileExists(lastConfigFileName()))
try
{
- rts::readRealOrBatchConfig(toZ(currentConfigFile), newConfig); //throw FfsXmlError
+ rts::readRealOrBatchConfig(currentConfigFile, newConfig); //throw FfsXmlError
loadCfgSuccess = true;
}
catch (const xmlAccess::FfsXmlError& error)
{
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
+ wxMessageBox(error.toString(),L"RealtimeSync" + _("Warning"), wxOK | wxICON_WARNING, this);
else
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
+ wxMessageBox(error.toString(), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR, this);
}
const bool startWatchingImmediately = loadCfgSuccess && !cfgFileName.empty();
@@ -127,11 +125,11 @@ MainDialog::~MainDialog()
try //write config to XML
{
- writeRealConfig(currentCfg, toZ(lastConfigFileName())); //throw FfsXmlError
+ writeRealConfig(currentCfg, lastConfigFileName()); //throw FfsXmlError
}
catch (const xmlAccess::FfsXmlError& error)
{
- wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
+ wxMessageBox(error.toString().c_str(), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR, this);
}
}
@@ -145,9 +143,9 @@ void MainDialog::onProcessAsyncTasks(wxEvent& event)
}
-const wxString& MainDialog::lastConfigFileName()
+const Zstring& MainDialog::lastConfigFileName()
{
- static wxString instance = toWx(zen::getConfigDir()) + L"LastRun.ffs_real";
+ static Zstring instance = zen::getConfigDir() + Zstr("LastRun.ffs_real");
return instance;
}
@@ -206,54 +204,59 @@ void MainDialog::OnStart(wxCommandEvent& event)
break;
}
Show(); //don't show for EXIT_APP
+ Raise();
}
void MainDialog::OnConfigSave(wxCommandEvent& event)
{
- wxString defaultFileName = currentConfigFileName.empty() ? L"Realtime.ffs_real" : currentConfigFileName;
+ Zstring defaultFileName = currentConfigFileName.empty() ? Zstr("Realtime.ffs_real") : currentConfigFileName;
//attention: currentConfigFileName may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
- if (endsWith(defaultFileName, L".ffs_batch"))
- replace(defaultFileName, L".ffs_batch", L".ffs_real", false);
+ if (endsWith(defaultFileName, Zstr(".ffs_batch")))
+ replace(defaultFileName, Zstr(".ffs_batch"), Zstr(".ffs_real"), false);
- wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, defaultFileName,
+ wxFileDialog filePicker(this,
+ wxEmptyString,
+ //OS X really needs dir/file separated like this:
+ utfCvrtTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR)), //default dir; empty string if / not found
+ utfCvrtTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR)), //default file; whole string if / not found
wxString(L"RealtimeSync (*.ffs_real)|*.ffs_real") + L"|" +_("All files") + L" (*.*)|*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (filePicker.ShowModal() != wxID_OK)
return;
- const wxString newFileName = filePicker.GetPath();
+ const Zstring newFileName = utfCvrtTo<Zstring>(filePicker.GetPath());
//write config to XML
const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
try
{
- writeRealConfig(currentCfg, toZ(newFileName)); //throw FfsXmlError
+ writeRealConfig(currentCfg, newFileName); //throw FfsXmlError
setLastUsedConfig(newFileName);
}
catch (const xmlAccess::FfsXmlError& e)
{
- wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this);
+ wxMessageBox(e.toString().c_str(), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR, this);
}
}
-void MainDialog::loadConfig(const wxString& filename)
+void MainDialog::loadConfig(const Zstring& filename)
{
xmlAccess::XmlRealConfig newConfig;
try
{
- rts::readRealOrBatchConfig(toZ(filename), newConfig);
+ rts::readRealOrBatchConfig(filename, newConfig);
}
catch (const xmlAccess::FfsXmlError& error)
{
if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING)
- wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this);
+ wxMessageBox(error.toString(), L"RealtimeSync" + _("Warning"), wxOK | wxICON_WARNING, this);
else
{
- wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this);
+ wxMessageBox(error.toString(), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR, this);
return;
}
}
@@ -263,7 +266,7 @@ void MainDialog::loadConfig(const wxString& filename)
}
-void MainDialog::setLastUsedConfig(const wxString& filename)
+void MainDialog::setLastUsedConfig(const Zstring& filename)
{
//set title
if (filename == lastConfigFileName())
@@ -273,7 +276,7 @@ void MainDialog::setLastUsedConfig(const wxString& filename)
}
else
{
- SetTitle(filename);
+ SetTitle(utfCvrtTo<wxString>(filename));
currentConfigFileName = filename;
}
}
@@ -281,11 +284,14 @@ void MainDialog::setLastUsedConfig(const wxString& filename)
void MainDialog::OnConfigLoad(wxCommandEvent& event)
{
- wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, wxEmptyString,
+ wxFileDialog filePicker(this,
+ wxEmptyString,
+ utfCvrtTo<wxString>(beforeLast(currentConfigFileName, FILE_NAME_SEPARATOR)), //default dir; empty string if / not found
+ wxEmptyString,
wxString(L"RealtimeSync (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch") + L"|" +_("All files") + L" (*.*)|*",
wxFD_OPEN);
if (filePicker.ShowModal() == wxID_OK)
- loadConfig(filePicker.GetPath());
+ loadConfig(utfCvrtTo<Zstring>(filePicker.GetPath()));
}
@@ -293,7 +299,7 @@ void MainDialog::onFilesDropped(FileDropEvent& event)
{
const auto& files = event.getFiles();
if (!files.empty())
- loadConfig(files[0]);
+ loadConfig(utfCvrtTo<Zstring>(files[0]));
}
@@ -307,14 +313,14 @@ void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg)
if (!cfg.directories.empty())
{
//fill top folder
- dirNameFirst->setName(*cfg.directories.begin());
+ dirNameFirst->setName(utfCvrtTo<wxString>(*cfg.directories.begin()));
//fill additional folders
- addFolder(std::vector<wxString>(cfg.directories.begin() + 1, cfg.directories.end()));
+ addFolder(std::vector<Zstring>(cfg.directories.begin() + 1, cfg.directories.end()));
}
//fill commandline
- m_textCtrlCommand->SetValue(cfg.commandline);
+ m_textCtrlCommand->SetValue(utfCvrtTo<wxString>(cfg.commandline));
//set delay
m_spinCtrlDelay->SetValue(static_cast<int>(cfg.delay));
@@ -325,11 +331,11 @@ xmlAccess::XmlRealConfig MainDialog::getConfiguration()
{
xmlAccess::XmlRealConfig output;
- output.directories.push_back(dirNameFirst->getName());
- for (std::vector<DirectoryPanel*>::const_iterator i = dirNamesExtra.begin(); i != dirNamesExtra.end(); ++i)
- output.directories.push_back((*i)->getName());
+ output.directories.push_back(utfCvrtTo<Zstring>(dirNameFirst->getName()));
+ for (auto it = dirNamesExtra.begin(); it != dirNamesExtra.end(); ++it)
+ output.directories.push_back(utfCvrtTo<Zstring>((*it)->getName()));
- output.commandline = m_textCtrlCommand->GetValue();
+ output.commandline = utfCvrtTo<Zstring>(m_textCtrlCommand->GetValue());
output.delay = m_spinCtrlDelay->GetValue();
return output;
@@ -338,12 +344,12 @@ xmlAccess::XmlRealConfig MainDialog::getConfiguration()
void MainDialog::OnAddFolder(wxCommandEvent& event)
{
- const wxString topFolder = dirNameFirst->getName();
+ const Zstring topFolder = utfCvrtTo<Zstring>(dirNameFirst->getName());
//clear existing top folder first
dirNameFirst->setName(wxString());
- std::vector<wxString> newFolders;
+ std::vector<Zstring> newFolders;
newFolders.push_back(topFolder);
addFolder(newFolders, true); //add pair in front of additonal pairs
@@ -383,7 +389,7 @@ static const size_t MAX_ADD_FOLDERS = 6;
#endif
-void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFront)
+void MainDialog::addFolder(const std::vector<Zstring>& newFolders, bool addFront)
{
if (newFolders.size() == 0)
return;
@@ -391,7 +397,7 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron
wxWindowUpdateLocker dummy(this); //avoid display distortion
int folderHeight = 0;
- for (std::vector<wxString>::const_iterator i = newFolders.begin(); i != newFolders.end(); ++i)
+ for (auto it = newFolders.begin(); it != newFolders.end(); ++it)
{
//add new folder pair
DirectoryPanel* newFolder = new DirectoryPanel(m_scrolledWinFolders);
@@ -415,7 +421,7 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron
newFolder->m_bpButtonRemoveFolder->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MainDialog::OnRemoveFolder), nullptr, this );
//insert directory name
- newFolder->setName(*i);
+ newFolder->setName(utfCvrtTo<wxString>(*it));
}
//set size of scrolled window
diff --git a/RealtimeSync/main_dlg.h b/RealtimeSync/main_dlg.h
index 5a028f3a..2a1fb03e 100644
--- a/RealtimeSync/main_dlg.h
+++ b/RealtimeSync/main_dlg.h
@@ -10,9 +10,10 @@
#include "gui_generated.h"
#include <vector>
#include <memory>
+#include <zen/zstring.h>
+#include <zen/async_task.h>
#include <wx+/file_drop.h>
#include "../ui/dir_name.h"
-#include <zen/async_task.h>
namespace xmlAccess
{
@@ -24,11 +25,11 @@ class DirectoryPanel;
class MainDialog: public MainDlgGenerated
{
public:
- MainDialog(wxDialog* dlg, const wxString& cfgFileName);
+ MainDialog(wxDialog* dlg, const Zstring& cfgFileName);
~MainDialog();
private:
- void loadConfig(const wxString& filename);
+ void loadConfig(const Zstring& filename);
virtual void OnClose (wxCloseEvent& event) { Destroy(); }
virtual void OnShowHelp (wxCommandEvent& event);
@@ -45,21 +46,21 @@ private:
void setConfiguration(const xmlAccess::XmlRealConfig& cfg);
xmlAccess::XmlRealConfig getConfiguration();
- void setLastUsedConfig(const wxString& filename);
+ void setLastUsedConfig(const Zstring& filename);
void layoutAsync(); //call Layout() asynchronously
- void addFolder(const wxString& dirname, bool addFront = false);
- void addFolder(const std::vector<wxString>& newFolders, bool addFront = false);
+ //void addFolder(const Zstring& dirname, bool addFront = false);
+ void addFolder(const std::vector<Zstring>& newFolders, bool addFront = false);
void removeAddFolder(size_t pos);
void clearAddFolders();
- static const wxString& lastConfigFileName();
+ static const Zstring& lastConfigFileName();
std::unique_ptr<zen::DirectoryName<wxTextCtrl>> dirNameFirst;
std::vector<DirectoryPanel*> dirNamesExtra; //additional pairs to the standard pair
- wxString currentConfigFileName;
+ Zstring currentConfigFileName;
void onProcessAsyncTasks(wxEvent& event);
diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile
index 865d73a1..d84c425f 100644
--- a/RealtimeSync/makefile
+++ b/RealtimeSync/makefile
@@ -58,7 +58,7 @@ CPP_LIST+=gui_generated.cpp
CPP_LIST+=main_dlg.cpp
CPP_LIST+=resources.cpp
CPP_LIST+=tray_menu.cpp
-CPP_LIST+=watcher.cpp
+CPP_LIST+=monitor.cpp
CPP_LIST+=xml_ffs.cpp
CPP_LIST+=xml_proc.cpp
CPP_LIST+=../structures.cpp
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/monitor.cpp
index 6ef5e924..88536281 100644
--- a/RealtimeSync/watcher.cpp
+++ b/RealtimeSync/monitor.cpp
@@ -4,16 +4,14 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#include "watcher.h"
+#include "monitor.h"
+#include <ctime>
#include <set>
-#include <zen/tick_count.h>
#include <zen/file_handling.h>
-#include <zen/stl_tools.h>
#include <zen/dir_watcher.h>
#include <zen/thread.h>
-#include <zen/assert_static.h>
#include <zen/tick_count.h>
-#include <wx+/string_conv.h>
+#include <wx/utils.h>
#include "../lib/resolve_path.h"
//#include "../library/db_file.h" //SYNC_DB_FILE_ENDING -> complete file too much of a dependency; file ending too little to decouple into single header
//#include "../library/lock_holder.h" //LOCK_FILE_ENDING
@@ -23,24 +21,6 @@ using namespace zen;
namespace
{
-const std::int64_t TICKS_UPDATE_INTERVAL = rts::UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
-TickVal lastExec = getTicks();
-};
-
-bool rts::updateUiIsAllowed()
-{
- const TickVal now = getTicks(); //0 on error
- if (dist(lastExec, now) >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary
- {
- lastExec = now;
- return true;
- }
- return false;
-}
-
-
-namespace
-{
const int CHECK_DIR_INTERVAL = 1; //unit: [s]
@@ -53,10 +33,28 @@ std::vector<Zstring> getFormattedDirs(const std::vector<Zstring>& dirs) //throw
return std::vector<Zstring>(tmp.begin(), tmp.end());
}
-}
-rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError
+//wait until changes are detected or if a directory is not available (anymore)
+struct WaitResult
+{
+ enum ChangeType
+ {
+ CHANGE_DETECTED,
+ CHANGE_DIR_MISSING
+ };
+
+ WaitResult(const zen::DirWatcher::Entry& changedItem) : type(CHANGE_DETECTED), changedItem_(changedItem) {}
+ WaitResult(const Zstring& dirname) : type(CHANGE_DIR_MISSING), dirname_(dirname) {}
+
+ ChangeType type;
+ zen::DirWatcher::Entry changedItem_; //for type == CHANGE_DETECTED: file or directory
+ Zstring dirname_; //for type == CHANGE_DIR_MISSING
+};
+
+
+WaitResult waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, //throw FileError
+ const std::function<void(bool)>& onRefreshGui) //bool: readyForSync
{
const std::vector<Zstring> dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError
if (dirNamesFmt.empty()) //pathological case, but we have to check else this function will wait endlessly
@@ -72,20 +70,17 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
{
//a non-existent network path may block, so check existence asynchronously!
auto ftDirExists = async([=] { return zen::dirExists(dirnameFmt); });
- while (!ftDirExists.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
- statusHandler.requestUiRefresh(); //may throw!
+ //we need to check dirExists(), not somethingExists(): it's not clear if DirWatcher detects a type clash (file instead of directory!)
+ while (!ftDirExists.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL / 2)))
+ onRefreshGui(false); //may throw!
if (!ftDirExists.get())
return WaitResult(dirnameFmt);
- watches.push_back(std::make_pair(dirnameFmt, std::make_shared<DirWatcher>(dirnameFmt))); //throw FileError, ErrorNotExisting
+ watches.push_back(std::make_pair(dirnameFmt, std::make_shared<DirWatcher>(dirnameFmt))); //throw FileError
}
- catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!!
+ catch (FileError&)
{
- return WaitResult(dirnameFmt);
- }
- catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing)
- {
- if (!dirExists(dirnameFmt)) //file system race condition!!
+ if (!somethingExists(dirnameFmt)) //a benign(?) race condition with FileError
return WaitResult(dirnameFmt);
throw;
}
@@ -114,12 +109,11 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
//IMPORTANT CHECK: dirwatcher has problems detecting removal of top watched directories!
if (checkDirExistNow)
- if (!dirExists(dirname)) //catch errors related to directory removal, e.g. ERROR_NETNAME_DELETED
+ if (!dirExists(dirname)) //catch errors related to directory removal, e.g. ERROR_NETNAME_DELETED -> somethingExists() is NOT sufficient here!
return WaitResult(dirname);
-
try
{
- std::vector<DirWatcher::Entry> changedItems = watcher.getChanges([&] { statusHandler.requestUiRefresh(); }); //throw FileError, ErrorNotExisting
+ std::vector<DirWatcher::Entry> changedItems = watcher.getChanges([&] { onRefreshGui(false); /*may throw!*/ }); //throw FileError
//remove to be ignored changes
vector_remove_if(changedItems, [](const DirWatcher::Entry& e)
@@ -139,26 +133,23 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
}
}
- catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!!
+ catch (FileError&)
{
- return WaitResult(dirname);
- }
- catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing)
- {
- if (!dirExists(dirname)) //file system race condition!!
+ if (!somethingExists(dirname)) //a benign(?) race condition with FileError
return WaitResult(dirname);
throw;
}
}
boost::this_thread::sleep(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL / 2));
- statusHandler.requestUiRefresh(true); //throw ?: may start sync at this presumably idle time
+ onRefreshGui(true); //throw ?: may start sync at this presumably idle time
}
}
-//support for monitoring newly connected directories volumes (e.g.: USB-sticks)
-void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError
+//wait until all directories become available (again) + logs in network share
+void waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, //throw FileError
+ const std::function<void(const Zstring&)>& onRefreshGui) //Zstring: the directory that is currently being waited for
{
while (true)
{
@@ -179,24 +170,112 @@ void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCal
return zen::dirExists(dirnameFmt);
});
while (!ftDirExisting.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL / 2)))
- statusHandler.requestUiRefresh(); //may throw!
+ onRefreshGui(dirnameFmt); //may throw!
if (!ftDirExisting.get())
{
allExisting = false;
+ //wait some time...
+ const int refreshInterval = rts::UI_UPDATE_INTERVAL / 2;
+ assert_static(CHECK_DIR_INTERVAL * 1000 % refreshInterval == 0);
+ for (int i = 0; i < CHECK_DIR_INTERVAL * 1000 / refreshInterval; ++i)
+ {
+ onRefreshGui(dirnameFmt); //may throw!
+ boost::this_thread::sleep(boost::posix_time::milliseconds(refreshInterval));
+ }
break;
}
}
if (allExisting)
return;
+ }
+}
+
+
+inline
+wxString toString(DirWatcher::ActionType type)
+{
+ switch (type)
+ {
+ case DirWatcher::ACTION_CREATE:
+ return L"CREATE";
+ case DirWatcher::ACTION_UPDATE:
+ return L"UPDATE";
+ case DirWatcher::ACTION_DELETE:
+ return L"DELETE";
+ }
+ return L"ERROR";
+}
+
+struct ExecCommandNowException {};
+}
+
+
+void rts::monitorDirectories(const std::vector<Zstring>& dirNamesNonFmt, unsigned int delay, rts::MonitorCallback& callback)
+{
+ if (dirNamesNonFmt.empty())
+ {
+ assert(false);
+ return;
+ }
+
+ auto execMonitoring = [&] //throw FileError
+ {
+ callback.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
+ waitForMissingDirs(dirNamesNonFmt, [&](const Zstring& dirname) { callback.requestUiRefresh(); }); //throw FileError
+ callback.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
+
+ //schedule initial execution (*after* all directories have arrived, which could take some time which we don't want to include)
+ time_t nextExecDate = std::time(nullptr) + delay;
+
+ while (true) //loop over command invocations
+ {
+ DirWatcher::Entry lastChangeDetected;
+ try
+ {
+ while (true) //loop over detected changes
+ {
+ //wait for changes (and for all directories to become available)
+ WaitResult res = waitForChanges(dirNamesNonFmt, [&](bool readyForSync) //throw FileError, ExecCommandNowException
+ {
+ if (readyForSync)
+ if (nextExecDate <= std::time(nullptr))
+ throw ExecCommandNowException(); //abort wait and start sync
+ callback.requestUiRefresh();
+ });
+ switch (res.type)
+ {
+ case WaitResult::CHANGE_DIR_MISSING: //don't execute the command before all directories are available!
+ callback.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
+ waitForMissingDirs(dirNamesNonFmt, [&](const Zstring& dirname) { callback.requestUiRefresh(); }); //throw FileError
+ callback.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
+ break;
+
+ case WaitResult::CHANGE_DETECTED:
+ lastChangeDetected = res.changedItem_;
+ break;
+ }
+ nextExecDate = std::time(nullptr) + delay;
+ }
+ }
+ catch (ExecCommandNowException&) {}
+
+ ::wxSetEnv(L"change_path", utfCvrtTo<wxString>(lastChangeDetected.filename_)); //some way to output what file changed to the user
+ ::wxSetEnv(L"change_action", toString(lastChangeDetected.action_)); //
- //wait some time...
- const int refreshInterval = UI_UPDATE_INTERVAL / 2;
- assert_static(1000 * CHECK_DIR_INTERVAL % refreshInterval == 0);
- for (int i = 0; i < 1000 * CHECK_DIR_INTERVAL / refreshInterval; ++i)
+ //execute command
+ callback.executeExternalCommand();
+ nextExecDate = std::numeric_limits<time_t>::max();
+ }
+ };
+
+ while (true)
+ try
{
- boost::this_thread::sleep(boost::posix_time::milliseconds(refreshInterval));
- statusHandler.requestUiRefresh();
+ execMonitoring(); //throw FileError
+ }
+ catch (const zen::FileError& e)
+ {
+ callback.reportError(e.toString());
}
- }
}
diff --git a/RealtimeSync/monitor.h b/RealtimeSync/monitor.h
new file mode 100644
index 00000000..0b9dfbc0
--- /dev/null
+++ b/RealtimeSync/monitor.h
@@ -0,0 +1,38 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef MONITOR_HEADER_345087425834253425
+#define MONITOR_HEADER_345087425834253425
+
+#include <functional>
+#include <zen/zstring.h>
+
+namespace rts
+{
+const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
+
+
+struct MonitorCallback
+{
+ virtual ~MonitorCallback() {}
+
+ enum WatchPhase
+ {
+ MONITOR_PHASE_ACTIVE,
+ MONITOR_PHASE_WAITING,
+ };
+ virtual void setPhase(WatchPhase mode) = 0;
+ virtual void executeExternalCommand() = 0;
+ virtual void requestUiRefresh() = 0;
+ virtual void reportError(const std::wstring& msg) = 0; //automatically retries after return!
+};
+void monitorDirectories(const std::vector<Zstring>& dirNamesNonFmt,
+ //non-formatted dirnames that yet require call to getFormattedDirectoryName(); empty directories must be checked by caller!
+ unsigned int delay,
+ MonitorCallback& callback);
+}
+
+#endif //MONITOR_HEADER_345087425834253425
diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp
index 676904f1..33758ad2 100644
--- a/RealtimeSync/tray_menu.cpp
+++ b/RealtimeSync/tray_menu.cpp
@@ -5,28 +5,20 @@
// **************************************************************************
#include "tray_menu.h"
-#include <algorithm>
-#include <iterator>
-#include <limits>
-#include <set>
-#include <zen/assert_static.h>
#include <zen/build_info.h>
+#include <zen/tick_count.h>
+#include <zen/thread.h>
#include <wx+/mouse_move_dlg.h>
#include <wx+/image_tools.h>
-#include <wx+/string_conv.h>
+//#include <wx+/string_conv.h>
#include <wx+/shell_execute.h>
#include <wx+/std_button_order.h>
-#include <wx/msgdlg.h>
#include <wx/taskbar.h>
-#include <wx/app.h>
-#include <wx/utils.h>
-#include <wx/menu.h>
-#include <wx/utils.h>
#include <wx/icon.h> //Linux needs this
-#include <wx/timer.h>
+#include <wx/app.h>
#include "resources.h"
#include "gui_generated.h"
-#include "watcher.h"
+#include "monitor.h"
#include "../lib/resolve_path.h"
using namespace rts;
@@ -35,67 +27,149 @@ using namespace zen;
namespace
{
-struct AbortCallback //never throw exceptions through a C-Layer (GUI)!
+const std::int64_t TICKS_UPDATE_INTERVAL = rts::UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
+TickVal lastExec = getTicks();
+
+bool updateUiIsAllowed()
+{
+ const TickVal now = getTicks(); //0 on error
+ if (dist(lastExec, now) >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary
+ {
+ lastExec = now;
+ return true;
+ }
+ return false;
+}
+
+
+enum TrayMode
{
- virtual ~AbortCallback() {}
- virtual void requestResume() = 0;
- virtual void requestAbort() = 0;
+ TRAY_MODE_ACTIVE,
+ TRAY_MODE_WAITING,
+ TRAY_MODE_ERROR,
};
-//RtsTrayIcon is a dumb class whose sole purpose is to enable wxWidgets deferred deletion
-class RtsTrayIconRaw : public wxTaskBarIcon
+class TrayIconObject : public wxTaskBarIcon
{
public:
- RtsTrayIconRaw(AbortCallback& abortCb) : abortCb_(&abortCb)
+ TrayIconObject(const wxString& jobname) :
+ resumeRequested(false),
+ abortRequested(false),
+ showErrorMsgRequested(false),
+ mode(TRAY_MODE_ACTIVE),
+ iconFlashStatusLast(false),
+ jobName_(jobname),
+#if defined ZEN_WIN || defined ZEN_MAC //16x16 seems to be the only size that is shown correctly on OS X
+ trayBmp(getResourceImage(L"RTS_tray_16x16")) //use a 16x16 bitmap
+#elif defined ZEN_LINUX
+ trayBmp(getResourceImage(L"RTS_tray_24x24")) //use a 24x24 bitmap for perfect fit
+#endif
{
- Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIconRaw::OnDoubleClick), nullptr, this);
+ Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconObject::OnDoubleClick), nullptr, this);
+ setMode(mode);
}
- void dontCallBackAnymore() { abortCb_ = nullptr; } //call before tray icon is marked for deferred deletion
+ //require polling:
+ bool resumeIsRequested() const { return resumeRequested; }
+ bool abortIsRequested () const { return abortRequested; }
+
+ //during TRAY_MODE_ERROR those two functions are available:
+ void clearShowErrorRequested() { assert(mode == TRAY_MODE_ERROR); showErrorMsgRequested = false; }
+ bool getShowErrorRequested() const { assert(mode == TRAY_MODE_ERROR); return showErrorMsgRequested; }
+
+ void setMode(TrayMode m)
+ {
+ mode = m;
+ timer.Stop();
+ timer.Disconnect(wxEVT_TIMER, wxEventHandler(TrayIconObject::OnErrorFlashIcon), nullptr, this);
+ switch (m)
+ {
+ case TRAY_MODE_ACTIVE:
+ setTrayIcon(trayBmp, _("Directory monitoring active"));
+ break;
+
+ case TRAY_MODE_WAITING:
+ setTrayIcon(greyScale(trayBmp), _("Waiting until all directories are available..."));
+ break;
+
+ case TRAY_MODE_ERROR:
+ timer.Connect(wxEVT_TIMER, wxEventHandler(TrayIconObject::OnErrorFlashIcon), nullptr, this);
+ timer.Start(500); //timer interval in [ms]
+ break;
+ }
+ }
private:
+ void OnErrorFlashIcon(wxEvent& event)
+ {
+ iconFlashStatusLast = !iconFlashStatusLast;
+ setTrayIcon(iconFlashStatusLast ? trayBmp : greyScale(trayBmp), _("Error"));
+ }
+
+ void setTrayIcon(const wxBitmap& bmp, const wxString& statusTxt)
+ {
+ wxIcon realtimeIcon;
+ realtimeIcon.CopyFromBitmap(bmp);
+ wxString tooltip = L"RealtimeSync\n" + statusTxt;
+ if (!jobName_.empty())
+ tooltip += L"\n\"" + jobName_ + L"\"";
+ SetIcon(realtimeIcon, tooltip);
+ }
+
enum Selection
{
- CONTEXT_RESTORE = 1, //wxWidgets: "A MenuItem ID of Zero does not work under Mac"
+ CONTEXT_RESTORE = 1, //wxWidgets: "A MenuItem ID of zero does not work under Mac"
+ CONTEXT_SHOW_ERROR,
CONTEXT_ABORT = wxID_EXIT,
CONTEXT_ABOUT = wxID_ABOUT
};
virtual wxMenu* CreatePopupMenu()
{
- if (!abortCb_)
- return nullptr;
-
wxMenu* contextMenu = new wxMenu;
- contextMenu->Append(CONTEXT_RESTORE, _("&Restore"));
+ switch (mode)
+ {
+ case TRAY_MODE_ACTIVE:
+ case TRAY_MODE_WAITING:
+ contextMenu->Append(CONTEXT_RESTORE, _("&Restore"));
+ break;
+ case TRAY_MODE_ERROR:
+ contextMenu->Append(CONTEXT_SHOW_ERROR, _("&Show error"));
+ break;
+ }
contextMenu->Append(CONTEXT_ABOUT, _("&About"));
contextMenu->AppendSeparator();
contextMenu->Append(CONTEXT_ABORT, _("&Exit"));
//event handling
- contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RtsTrayIconRaw::OnContextMenuSelection), nullptr, this);
+ contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TrayIconObject::OnContextMenuSelection), nullptr, this);
return contextMenu; //ownership transferred to caller
}
void OnContextMenuSelection(wxCommandEvent& event)
{
- if (!abortCb_)
- return;
-
switch (static_cast<Selection>(event.GetId()))
{
case CONTEXT_ABORT:
- abortCb_->requestAbort();
+ abortRequested = true;
break;
case CONTEXT_RESTORE:
- abortCb_->requestResume();
+ resumeRequested = true;
+ break;
+
+ case CONTEXT_SHOW_ERROR:
+ showErrorMsgRequested = true;
break;
case CONTEXT_ABOUT:
{
- //build information
+ //ATTENTION: the modal dialog below does NOT disable all GUI input, e.g. user may still double-click on tray icon
+ //no crash in this context, but the double-click is remembered and executed after the modal dialog quits
+ SetEvtHandlerEnabled(false);
+ ZEN_ON_SCOPE_EXIT(SetEvtHandlerEnabled(true));
+
wxString build = __TDATE__;
#if wxUSE_UNICODE
build += L" - Unicode";
@@ -103,7 +177,6 @@ private:
build += L" - ANSI";
#endif //wxUSE_UNICODE
- //compile time info about 32/64-bit build
if (zen::is64BitBuild)
build += L" x64";
else
@@ -118,136 +191,86 @@ private:
void OnDoubleClick(wxCommandEvent& event)
{
- if (abortCb_)
- abortCb_->requestResume();
- }
-
- AbortCallback* abortCb_;
-};
-
-
-class TrayIconHolder
-{
-public:
- TrayIconHolder(const wxString& jobname, AbortCallback& abortCb) :
- jobName_(jobname),
- trayMenu(new RtsTrayIconRaw(abortCb))
- {
- showIconActive();
+ switch (mode)
+ {
+ case TRAY_MODE_ACTIVE:
+ case TRAY_MODE_WAITING:
+ resumeRequested = true; //never throw exceptions through a C-Layer call stack (GUI)!
+ break;
+ case TRAY_MODE_ERROR:
+ showErrorMsgRequested = true;
+ break;
+ }
}
- ~TrayIconHolder()
- {
- trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place
- trayMenu->dontCallBackAnymore();
+ bool resumeRequested;
+ bool abortRequested;
+ bool showErrorMsgRequested;
- //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
- if (!wxPendingDelete.Member(trayMenu))
- wxPendingDelete.Append(trayMenu);
- }
+ TrayMode mode;
- void doUiRefreshNow()
- {
- wxTheApp->Yield();
- } //yield is UI-layer which is represented by this tray icon
+ bool iconFlashStatusLast; //flash try icon for TRAY_MODE_ERROR
+ wxTimer timer; //
- void showIconActive()
- {
- wxIcon realtimeIcon;
-#if defined ZEN_WIN || defined ZEN_MAC //16x16 seems to be the only size that is shown correctly on OS X
- realtimeIcon.CopyFromBitmap(getResourceImage(L"RTS_tray_16x16")); //use a 16x16 bitmap
-#elif defined ZEN_LINUX
- realtimeIcon.CopyFromBitmap(getResourceImage(L"RTS_tray_24x24")); //use a 24x24 bitmap for perfect fit
-#endif
- wxString tooltip = L"RealtimeSync";
- if (!jobName_.empty())
- tooltip += L"\n\"" + jobName_ + L"\"";
- trayMenu->SetIcon(realtimeIcon, tooltip);
- }
-
- void showIconWaiting()
- {
- wxIcon realtimeIcon;
-#if defined ZEN_WIN || defined ZEN_MAC
- realtimeIcon.CopyFromBitmap(greyScale(getResourceImage(L"RTS_tray_16x16")));
-#elif defined ZEN_LINUX
- realtimeIcon.CopyFromBitmap(greyScale(getResourceImage(L"RTS_tray_24x24")));
-#endif
- wxString tooltip = _("Waiting for missing directories...");
- if (!jobName_.empty())
- tooltip += L"\n\"" + jobName_ + L"\"";
- trayMenu->SetIcon(realtimeIcon, tooltip);
- }
-
-private:
const wxString jobName_; //RTS job name, may be empty
- RtsTrayIconRaw* trayMenu;
+ const wxBitmap trayBmp;
};
-//##############################################################################################################
-
-struct AbortMonitoring//exception class
+struct AbortMonitoring //exception class
{
AbortMonitoring(AbortReason reasonCode) : reasonCode_(reasonCode) {}
AbortReason reasonCode_;
};
-class StartSyncNowException {};
-
-//##############################################################################################################
-class WaitCallbackImpl : public rts::WaitCallback, private AbortCallback
+//=> don't derive from wxEvtHandler or any other wxWidgets object unless instance is safely deleted (deferred) during idle event!!tray_icon.h
+class TrayIconHolder
{
public:
- WaitCallbackImpl(const wxString& jobname) :
- trayIcon(jobname, *this),
- nextSyncStart_(std::numeric_limits<long>::max()),
- resumeRequested(false),
- abortRequested(false) {}
-
- void notifyAllDirectoriesExist() { trayIcon.showIconActive(); }
- void notifyDirectoryMissing () { trayIcon.showIconWaiting(); }
+ TrayIconHolder(const wxString& jobname) :
+ trayObj(new TrayIconObject(jobname)) {}
- void scheduleNextSync(long nextSyncStart) { nextSyncStart_ = nextSyncStart; }
- void clearSchedule() { nextSyncStart_ = std::numeric_limits<long>::max(); }
+ ~TrayIconHolder()
+ {
+ //harmonize with tray_icon.cpp!!!
+ trayObj->RemoveIcon();
+ //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
+ wxPendingDelete.Append(trayObj);
+ }
- //implement WaitCallback
- virtual void requestUiRefresh(bool readyForSync) //throw StartSyncNowException, AbortMonitoring
+ void doUiRefreshNow() //throw AbortMonitoring
{
- if (resumeRequested)
+ wxTheApp->Yield(); //yield is UI-layer which is represented by this tray icon
+
+ //advantage of polling vs callbacks: we can throw exceptions!
+ if (trayObj->resumeIsRequested())
throw AbortMonitoring(SHOW_GUI);
- if (abortRequested)
+ if (trayObj->abortIsRequested())
throw AbortMonitoring(EXIT_APP);
+ }
- if (readyForSync)
- if (nextSyncStart_ <= wxGetLocalTime())
- throw StartSyncNowException(); //abort wait and start sync
+ void setMode(TrayMode m) { trayObj->setMode(m); }
- if (updateUiIsAllowed())
- trayIcon.doUiRefreshNow();
- }
+ bool getShowErrorRequested() const { return trayObj->getShowErrorRequested(); }
+ void clearShowErrorRequested() { trayObj->clearShowErrorRequested(); }
private:
- //implement AbortCallback: used from C-GUI call stack
- virtual void requestResume() { resumeRequested = true; }
- virtual void requestAbort () { abortRequested = true; }
-
- TrayIconHolder trayIcon;
- long nextSyncStart_;
- bool resumeRequested;
- bool abortRequested;
+ TrayIconObject* trayObj;
};
+//##############################################################################################################
-
+//#define ERROR_DLG_ENABLE_TIMEOUT
class ErrorDlgWithTimeout : public ErrorDlgGenerated
{
public:
ErrorDlgWithTimeout(wxWindow* parent, const wxString& messageText) :
- ErrorDlgGenerated(parent),
- secondsLeft(15) //give user some time to read msg!?
+ ErrorDlgGenerated(parent)
+#ifdef ERROR_DLG_ENABLE_TIMEOUT
+ , secondsLeft(15) //give user some time to read msg!?
+#endif
{
#ifdef ZEN_WIN
new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
@@ -257,11 +280,12 @@ public:
m_bitmap10->SetBitmap(getResourceImage(L"msg_error"));
m_textCtrl8->SetValue(messageText);
+#ifdef ERROR_DLG_ENABLE_TIMEOUT
//count down X seconds then automatically press "retry"
timer.Connect(wxEVT_TIMER, wxEventHandler(ErrorDlgWithTimeout::OnTimerEvent), nullptr, this);
timer.Start(1000); //timer interval in ms
updateButtonLabel();
-
+#endif
Fit(); //child-element widths have changed: image was set
m_buttonRetry->SetFocus();
}
@@ -273,6 +297,7 @@ public:
};
private:
+#ifdef ERROR_DLG_ENABLE_TIMEOUT
void OnTimerEvent(wxEvent& event)
{
if (secondsLeft <= 0)
@@ -289,20 +314,23 @@ private:
m_buttonRetry->SetLabel(_("&Retry") + L" (" + replaceCpy(_P("1 sec", "%x sec", secondsLeft), L"%x", numberTo<std::wstring>(secondsLeft)) + L")");
Layout();
}
+#endif
void OnClose(wxCloseEvent& event) { EndModal(BUTTON_ABORT); }
void OnRetry(wxCommandEvent& event) { EndModal(BUTTON_RETRY); }
void OnAbort(wxCommandEvent& event) { EndModal(BUTTON_ABORT); }
+#ifdef ERROR_DLG_ENABLE_TIMEOUT
int secondsLeft;
wxTimer timer;
+#endif
};
-bool reportErrorTimeout(const std::wstring& msg) //return true if timeout or user selected "retry", else abort
+bool reportErrorTimeout(const std::wstring& msg) //return true: "retry"; false: "abort"
{
ErrorDlgWithTimeout errorDlg(nullptr, msg);
- //errorDlg.Raise(); -> don't steal focus every X seconds
+ errorDlg.Raise();
switch (static_cast<ErrorDlgWithTimeout::ButtonPressed>(errorDlg.ShowModal()))
{
case ErrorDlgWithTimeout::BUTTON_RETRY:
@@ -312,120 +340,90 @@ bool reportErrorTimeout(const std::wstring& msg) //return true if timeout or use
}
return false;
}
-
-
-inline
-wxString toString(DirWatcher::ActionType type)
-{
- switch (type)
- {
- case DirWatcher::ACTION_CREATE:
- return L"CREATE";
- case DirWatcher::ACTION_UPDATE:
- return L"UPDATE";
- case DirWatcher::ACTION_DELETE:
- return L"DELETE";
- }
- return L"ERROR";
-}
}
-/*
-Data Flow:
-----------
-
-TrayIconHolder (GUI output)
- /|\
- |
-WaitCallbackImpl
- /|\
- |
-startDirectoryMonitor() (wire dir-changes and execution of commandline)
-*/
-
rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname)
{
- std::vector<Zstring> dirList = toZ(config.directories);
- vector_remove_if(dirList, [](Zstring str) -> bool { trim(str); return str.empty(); }); //remove empty entries WITHOUT formatting dirList yet!
+ std::vector<Zstring> dirNamesNonFmt = config.directories;
+ vector_remove_if(dirNamesNonFmt, [](Zstring str) -> bool { trim(str); return str.empty(); }); //remove empty entries WITHOUT formatting paths yet!
- if (dirList.empty())
+ if (dirNamesNonFmt.empty())
{
- wxMessageBox(_("A folder input field is empty."), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(_("A folder input field is empty."), L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR);
return SHOW_GUI;
}
- wxString cmdLine = config.commandline;
+ Zstring cmdLine = config.commandline;
trim(cmdLine);
if (cmdLine.empty())
{
- wxMessageBox(_("Invalid command line:") + L" \"\"", _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(_("Invalid command line:") + L" \"\"", L"RealtimeSync" + _("Error"), wxOK | wxICON_ERROR);
return SHOW_GUI;
}
- try
+ struct MonitorCallbackImpl : public MonitorCallback
{
- DirWatcher::Entry lastChangeDetected;
- WaitCallbackImpl callback(jobname);
+ MonitorCallbackImpl(const wxString& jobname,
+ const Zstring& cmdLine) : trayIcon(jobname), cmdLine_(cmdLine) {}
+
+ virtual void setPhase(WatchPhase mode)
+ {
+ switch (mode)
+ {
+ case MONITOR_PHASE_ACTIVE:
+ trayIcon.setMode(TRAY_MODE_ACTIVE);
+ break;
+ case MONITOR_PHASE_WAITING:
+ trayIcon.setMode(TRAY_MODE_WAITING);
+ break;
+ }
+ }
- auto execMonitoring = [&] //throw FileError, AbortMonitoring
+ virtual void executeExternalCommand()
{
- callback.notifyDirectoryMissing();
- callback.clearSchedule();
- waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring
- callback.notifyAllDirectoriesExist();
+ auto cmdLineExp = expandMacros(cmdLine_);
+ zen::shellExecute(cmdLineExp, zen::EXEC_TYPE_SYNC);
+ }
- //schedule initial execution (*after* all directories have arrived, which could take some time which we don't want to include)
- callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay));
+ virtual void requestUiRefresh()
+ {
+ if (updateUiIsAllowed())
+ trayIcon.doUiRefreshNow(); //throw AbortMonitoring
+ }
+
+ virtual void reportError(const std::wstring& msg)
+ {
+ trayIcon.setMode(TRAY_MODE_ERROR);
+ trayIcon.clearShowErrorRequested();
- while (true)
+ //wait for some time, then return to retry
+ assert_static(15 * 1000 % UI_UPDATE_INTERVAL == 0);
+ for (int i = 0; i < 15 * 1000 / UI_UPDATE_INTERVAL; ++i)
{
- try
+ trayIcon.doUiRefreshNow(); //throw AbortMonitoring
+
+ if (trayIcon.getShowErrorRequested())
{
- while (true)
- {
- //wait for changes (and for all directories to become available)
- WaitResult res = waitForChanges(dirList, callback); //throw FileError, StartSyncNowException, AbortMonitoring
- switch (res.type)
- {
- case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available!
- callback.notifyDirectoryMissing();
- callback.clearSchedule();
- waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring
- callback.notifyAllDirectoriesExist();
- break;
-
- case CHANGE_DETECTED:
- lastChangeDetected = res.changedItem_;
- break;
- }
- callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay));
- }
+ if (reportErrorTimeout(msg)) //return true: "retry"; false: "abort"
+ return;
+ else
+ throw AbortMonitoring(SHOW_GUI);
}
- catch (StartSyncNowException&) {}
-
- ::wxSetEnv(L"change_path", utfCvrtTo<wxString>(lastChangeDetected.filename_)); //some way to output what file changed to the user
- ::wxSetEnv(L"change_action", toString(lastChangeDetected.action_)); //
- lastChangeDetected = DirWatcher::Entry(); //make sure old name is not shown again after a directory reappears
-
- //execute command
- auto cmdLineExp = expandMacros(utfCvrtTo<Zstring>(cmdLine));
- zen::shellExecute(cmdLineExp, zen::EXEC_TYPE_SYNC);
- callback.clearSchedule();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL));
}
- };
+ }
- while (true)
- try
- {
- execMonitoring(); //throw FileError, AbortMonitoring
- }
- catch (const zen::FileError& e)
- {
- if (!reportErrorTimeout(e.toString())) //return true if timeout or user selected "retry", else abort
- return SHOW_GUI;
- }
+ TrayIconHolder trayIcon;
+ const Zstring cmdLine_;
+ } cb(jobname, cmdLine);
+
+ try
+ {
+ monitorDirectories(dirNamesNonFmt, config.delay, cb); //cb: throw AbortMonitoring
+ assert(false);
+ return SHOW_GUI;
}
catch (const AbortMonitoring& ab)
{
diff --git a/RealtimeSync/tray_menu.h b/RealtimeSync/tray_menu.h
index 006dae82..1f71a017 100644
--- a/RealtimeSync/tray_menu.h
+++ b/RealtimeSync/tray_menu.h
@@ -4,13 +4,12 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef TRAYMENU_H_INCLUDED
-#define TRAYMENU_H_INCLUDED
+#ifndef TRAY_583967857420987534253245
+#define TRAY_583967857420987534253245
-#include "watcher.h"
+#include <wx/string.h>
#include "xml_proc.h"
-
namespace rts
{
enum AbortReason
@@ -21,5 +20,4 @@ enum AbortReason
AbortReason startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty
}
-
-#endif // TRAYMENU_H_INCLUDED
+#endif //TRAY_583967857420987534253245
diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h
deleted file mode 100644
index 2fd32119..00000000
--- a/RealtimeSync/watcher.h
+++ /dev/null
@@ -1,54 +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) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef WATCHER_H_INCLUDED
-#define WATCHER_H_INCLUDED
-
-#include <zen/dir_watcher.h>
-#include <zen/file_error.h>
-
-
-namespace rts
-{
-const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
-bool updateUiIsAllowed();
-
-
-class WaitCallback
-{
-public:
- virtual ~WaitCallback() {}
- virtual void requestUiRefresh(bool readyForSync = false) = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
-};
-
-
-//wait until changes are detected or if a directory is not available (anymore)
-enum ChangeType
-{
- CHANGE_DETECTED,
- CHANGE_DIR_MISSING
-};
-
-struct WaitResult
-{
- WaitResult(const zen::DirWatcher::Entry& changedItem) : type(CHANGE_DETECTED), changedItem_(changedItem) {}
- WaitResult(const Zstring& dirname) : type(CHANGE_DIR_MISSING), dirname_(dirname) {}
-
- ChangeType type;
- zen::DirWatcher::Entry changedItem_; //for type == CHANGE_DETECTED: file or directory
- Zstring dirname_; //for type == CHANGE_DIR_MISSING
-};
-
-WaitResult waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
- //non-formatted dirnames that yet require call to getFormattedDirectoryName(); empty directories must be checked by caller!
- WaitCallback& statusHandler); //throw FileError
-
-//wait until all directories become available (again) + logs in network share
-void waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt,
- WaitCallback& statusHandler); //throw FileError
-}
-
-#endif // WATCHER_H_INCLUDED
diff --git a/RealtimeSync/xml_ffs.cpp b/RealtimeSync/xml_ffs.cpp
index 1f3fb1b1..149b0bbe 100644
--- a/RealtimeSync/xml_ffs.cpp
+++ b/RealtimeSync/xml_ffs.cpp
@@ -7,7 +7,7 @@
#include "xml_ffs.h"
#include "../lib/ffs_paths.h"
#include <zen/zstring.h>
-#include <wx+/string_conv.h>
+//#include <wx+/string_conv.h>
//include FreeFileSync xml headers
#include "../lib/process_xml.h"
@@ -17,8 +17,6 @@ using namespace zen;
xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& batchCfg, const Zstring& filename)
{
- xmlAccess::XmlRealConfig output;
-
std::set<Zstring, LessFilename> uniqueFolders;
//add main folders
@@ -35,13 +33,9 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat
uniqueFolders.erase(Zstring());
- output.directories.clear();
- std::transform(uniqueFolders.begin(), uniqueFolders.end(), std::back_inserter(output.directories),
- [](const Zstring & fn) { return toWx(fn); });
-
- output.commandline = std::wstring(L"\"") + zen::getFreeFileSyncLauncher() + L"\"" +
- L" \"" + filename + L"\"";
-
+ xmlAccess::XmlRealConfig output;
+ output.directories.assign(uniqueFolders.begin(), uniqueFolders.end());
+ output.commandline = Zstr("\"") + zen::getFreeFileSyncLauncher() + Zstr("\" \"") + filename + Zstr("\"");
return output;
}
diff --git a/RealtimeSync/xml_proc.h b/RealtimeSync/xml_proc.h
index ab57e816..671a237f 100644
--- a/RealtimeSync/xml_proc.h
+++ b/RealtimeSync/xml_proc.h
@@ -8,7 +8,7 @@
#define XMLPROCESSING_H_INCLUDED
#include <vector>
-#include <wx/string.h>
+//#include <wx/string.h>
#include <zen/zstring.h>
#include "../lib/xml_base.h"
@@ -18,9 +18,9 @@ namespace xmlAccess
struct XmlRealConfig
{
XmlRealConfig() : delay(10) {}
- std::vector<wxString> directories;
- wxString commandline;
- size_t delay;
+ std::vector<Zstring> directories;
+ Zstring commandline;
+ unsigned int delay;
};
void readRealConfig(const Zstring& filename, XmlRealConfig& config); //throw FfsXmlError
bgstack15