diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:49 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:19:49 +0200 |
commit | c8e0e909b4a8d18319fc65434a10dc446434817c (patch) | |
tree | eee91e7d2ce229dd043811eae8f1e2bd78061916 /RealtimeSync | |
parent | 5.2 (diff) | |
download | FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.gz FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.tar.bz2 FreeFileSync-c8e0e909b4a8d18319fc65434a10dc446434817c.zip |
5.3
Diffstat (limited to 'RealtimeSync')
-rw-r--r-- | RealtimeSync/RealtimeSync.cbp | 2 | ||||
-rw-r--r-- | RealtimeSync/RealtimeSync.vcxproj | 59 | ||||
-rw-r--r-- | RealtimeSync/application.cpp | 24 | ||||
-rw-r--r-- | RealtimeSync/gui_generated.cpp | 66 | ||||
-rw-r--r-- | RealtimeSync/gui_generated.h | 30 | ||||
-rw-r--r-- | RealtimeSync/main_dlg.cpp | 109 | ||||
-rw-r--r-- | RealtimeSync/main_dlg.h | 22 | ||||
-rw-r--r-- | RealtimeSync/resources.cpp | 12 | ||||
-rw-r--r-- | RealtimeSync/tray_menu.cpp | 479 | ||||
-rw-r--r-- | RealtimeSync/tray_menu.h | 9 | ||||
-rw-r--r-- | RealtimeSync/watcher.cpp | 138 | ||||
-rw-r--r-- | RealtimeSync/watcher.h | 16 | ||||
-rw-r--r-- | RealtimeSync/xml_ffs.cpp | 6 | ||||
-rw-r--r-- | RealtimeSync/xml_ffs.h | 3 | ||||
-rw-r--r-- | RealtimeSync/xml_proc.cpp | 16 | ||||
-rw-r--r-- | RealtimeSync/xml_proc.h | 5 |
16 files changed, 550 insertions, 446 deletions
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index e1b46812..1a9469a8 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -81,7 +81,7 @@ <Add option="-DWXINTL_NO_GETTEXT_MACRO" /> <Add directory="C:\Programme\C++\wxWidgets\include" /> <Add directory="C:\Program Files\C++\Boost" /> - <Add directory="..\." /> + <Add directory=".." /> </Compiler> <ResourceCompiler> <Add directory="C:\Programme\C++\wxWidgets\include" /> diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj index f115bac4..8a062159 100644 --- a/RealtimeSync/RealtimeSync.vcxproj +++ b/RealtimeSync/RealtimeSync.vcxproj @@ -49,7 +49,7 @@ <UseDebugLibraries>false</UseDebugLibraries> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v110</PlatformToolset> + <PlatformToolset>Windows7.1SDK</PlatformToolset> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> @@ -71,15 +71,15 @@ <LinkIncremental>true</LinkIncremental> <OutDir>..\BUILD\Bin\</OutDir> <IntDir>..\OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir> - <TargetName>$(ProjectName)_$(PlatformName)</TargetName> <GenerateManifest>false</GenerateManifest> + <TargetName>$(ProjectName)_$(PlatformName)</TargetName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <LinkIncremental>true</LinkIncremental> <OutDir>..\BUILD\Bin\</OutDir> <IntDir>..\OBJ\$(ProjectName)_$(Configuration)_$(PlatformName)_VCPP\</IntDir> - <TargetName>$(ProjectName)_$(PlatformName)</TargetName> <GenerateManifest>false</GenerateManifest> + <TargetName>$(ProjectName)_$(PlatformName)</TargetName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> @@ -101,24 +101,21 @@ <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories> <PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings> - <MultiProcessorCompilation>false</MultiProcessorCompilation> - <DisableLanguageExtensions>false</DisableLanguageExtensions> + <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> <ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> - <SuppressStartupBanner>true</SuppressStartupBanner> <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++\wxWidgets\lib\vc_dll;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> - <LinkStatus> - </LinkStatus> </Link> <ResourceCompile> <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories> @@ -131,20 +128,19 @@ <WarningLevel>Level4</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..;C:\Program Files\C++\wxWidgets-x64-VC11\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_dll\mswud;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include;C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll\mswud;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories> <PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile> - <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings> - <MultiProcessorCompilation>false</MultiProcessorCompilation> - <DisableLanguageExtensions>false</DisableLanguageExtensions> + <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings> + <MultiProcessorCompilation>true</MultiProcessorCompilation> <PrecompiledHeaderOutputFile>$(IntDir)pch.obj</PrecompiledHeaderOutputFile> <ForcedIncludeFiles>zen/warn_static.h;wx+/pch.h</ForcedIncludeFiles> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <SuppressStartupBanner>true</SuppressStartupBanner> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <SubSystem>Windows</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> - <SuppressStartupBanner>true</SuppressStartupBanner> <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++\wxWidgets-x64-VC11\lib\vc_dll;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> @@ -162,14 +158,12 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> - <DisableLanguageExtensions>false</DisableLanguageExtensions> <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> </ClCompile> <Link> @@ -177,19 +171,13 @@ <GenerateDebugInformation>false</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <SuppressStartupBanner>true</SuppressStartupBanner> <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++\wxWidgets\lib\vc_lib;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> - <LinkStatus> - </LinkStatus> - <Profile>true</Profile> </Link> <ResourceCompile> <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>%(PreprocessorDefinitions);</PreprocessorDefinitions> - <Culture> - </Culture> </ResourceCompile> <PostBuildEvent> <Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command> @@ -201,15 +189,12 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..;C:\Program Files\C++\wxWidgets-x64-VC11\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> - <DisableSpecificWarnings>4100;4996;4267;4512</DisableSpecificWarnings> + <DisableSpecificWarnings>4100;4512</DisableSpecificWarnings> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <MultiProcessorCompilation>true</MultiProcessorCompilation> - <DisableLanguageExtensions>false</DisableLanguageExtensions> - <SuppressStartupBanner>true</SuppressStartupBanner> <ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles> </ClCompile> <Link> @@ -217,19 +202,13 @@ <GenerateDebugInformation>false</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <SuppressStartupBanner>true</SuppressStartupBanner> <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++\wxWidgets-x64-VC11\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> - <LinkStatus> - </LinkStatus> - <Profile>true</Profile> + <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories> </Link> <ResourceCompile> <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories> <PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions> - <Culture> - </Culture> </ResourceCompile> <PostBuildEvent> <Command>"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(TargetPath)"</Command> @@ -257,7 +236,6 @@ <ClCompile Include="application.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> - <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">wx+/pch.h</PrecompiledHeaderFile> </ClCompile> <ClCompile Include="gui_generated.cpp" /> <ClCompile Include="main_dlg.cpp" /> @@ -271,8 +249,9 @@ <ResourceCompile Include="resource.rc" /> </ItemGroup> <ItemGroup> - <None Include="ClassDiagram.cd" /> - <None Include="WxWizDialog.fbp" /> + <None Include="WxWizFrame.fbp"> + <SubType>Designer</SubType> + </None> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp index ead65eaa..4c477ce0 100644 --- a/RealtimeSync/application.cpp +++ b/RealtimeSync/application.cpp @@ -67,12 +67,12 @@ void Application::OnStartApplication(wxIdleEvent& event) if (!fileExists(filename)) //be a little tolerant { if (fileExists(filename + Zstr(".ffs_real"))) - filename = filename + Zstr(".ffs_real"); + filename += Zstr(".ffs_real"); else if (fileExists(filename + Zstr(".ffs_batch"))) - filename = filename + Zstr(".ffs_batch"); + filename += Zstr(".ffs_batch"); else { - wxMessageBox(wxString(_("File does not exist:")) + wxT(" \"") + toWx(filename) + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)), _("Error"), wxOK | wxICON_ERROR); return; } } @@ -103,11 +103,21 @@ int Application::OnRun() } catch (const std::exception& e) //catch all STL exceptions { - //unfortunately it's not always possible to display a message box in this erroneous situation, however (non-stream) file output always works! - wxFile safeOutput(toWx(zen::getConfigDir()) + wxT("LastError.txt"), wxFile::write); - safeOutput.Write(wxString::FromAscii(e.what())); + //it's not always possible to display a message box, e.g. corrupted stack, however (non-stream) file output works! + wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write); + safeOutput.Write(utf8CvrtTo<wxString>(e.what())); - wxSafeShowMessage(_("An exception occurred!") + L" - RTS", wxString::FromAscii(e.what())); + wxSafeShowMessage(_("An exception occurred!") + L" - RTS", utf8CvrtTo<wxString>(e.what())); + return -9; + } + catch (...) //catch the rest + { + const wxString& msg = L"Unknown error."; + + wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write); + safeOutput.Write(msg); + + wxSafeShowMessage(_("An exception occurred!"), msg); return -9; } diff --git a/RealtimeSync/gui_generated.cpp b/RealtimeSync/gui_generated.cpp index 849915a4..9bcbda52 100644 --- a/RealtimeSync/gui_generated.cpp +++ b/RealtimeSync/gui_generated.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Feb 9 2012) +// C++ code generated with wxFormBuilder (version Apr 10 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -164,7 +164,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( sbSizer4, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); - m_buttonStart = new zen::BitmapButton( m_panelMain, wxID_ANY, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 ); + m_buttonStart = new zen::BitmapButton( m_panelMain, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 ); m_buttonStart->SetDefault(); m_buttonStart->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) ); @@ -246,3 +246,65 @@ FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint FolderGenerated::~FolderGenerated() { } + +ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( 300,160 ), wxDefaultSize ); + + wxBoxSizer* bSizer24; + bSizer24 = new wxBoxSizer( wxVERTICAL ); + + + bSizer24->Add( 0, 10, 0, wxEXPAND, 5 ); + + wxBoxSizer* bSizer26; + bSizer26 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + bSizer26->Add( m_bitmap10, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE|wxTE_READONLY ); + m_textCtrl8->SetBackgroundColour( wxColour( 224, 224, 224 ) ); + + bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); + + + bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); + + wxBoxSizer* bSizer25; + bSizer25 = new wxBoxSizer( wxHORIZONTAL ); + + m_buttonRetry = new wxButton( this, wxID_RETRY, _("&Retry"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonRetry->SetDefault(); + m_buttonRetry->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + bSizer25->Add( m_buttonRetry, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + + m_buttonAbort = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + bSizer25->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + + + bSizer24->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + + this->SetSizer( bSizer24 ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ErrorDlgGenerated::OnClose ) ); + m_buttonRetry->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this ); + m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this ); +} + +ErrorDlgGenerated::~ErrorDlgGenerated() +{ + // Disconnect Events + this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ErrorDlgGenerated::OnClose ) ); + m_buttonRetry->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this ); + m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this ); + +} diff --git a/RealtimeSync/gui_generated.h b/RealtimeSync/gui_generated.h index aa0f5ad8..1989653f 100644 --- a/RealtimeSync/gui_generated.h +++ b/RealtimeSync/gui_generated.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Feb 9 2012) +// C++ code generated with wxFormBuilder (version Apr 10 2012) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -34,6 +34,8 @@ #include <wx/scrolwin.h> #include <wx/spinctrl.h> #include <wx/frame.h> +#include <wx/statbmp.h> +#include <wx/dialog.h> #include "../zen/i18n.h" @@ -111,4 +113,30 @@ public: }; +/////////////////////////////////////////////////////////////////////////////// +/// Class ErrorDlgGenerated +/////////////////////////////////////////////////////////////////////////////// +class ErrorDlgGenerated : public wxDialog +{ +private: + +protected: + wxStaticBitmap* m_bitmap10; + wxTextCtrl* m_textCtrl8; + wxButton* m_buttonRetry; + wxButton* m_buttonAbort; + + // Virtual event handlers, overide them in your derived class + virtual void OnClose( wxCloseEvent& event ) { event.Skip(); } + virtual void OnRetry( wxCommandEvent& event ) { event.Skip(); } + virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); } + + +public: + + ErrorDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Error"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 460,250 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER ); + ~ErrorDlgGenerated(); + +}; + #endif //__GUI_GENERATED_H__ diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp index c91e4856..dfb1a85e 100644 --- a/RealtimeSync/main_dlg.cpp +++ b/RealtimeSync/main_dlg.cpp @@ -59,15 +59,15 @@ MainDialog::MainDialog(wxDialog* dlg, const wxString& cfgFileName) if (!cfgFileName.empty() || wxFileExists(lastConfigFileName())) try { - rts::readRealOrBatchConfig(currentConfigFile, newConfig); + rts::readRealOrBatchConfig(toZ(currentConfigFile), newConfig); loadCfgSuccess = true; } catch (const xmlAccess::FfsXmlError& error) { if (error.getSeverity() == xmlAccess::FfsXmlError::WARNING) - wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING); + wxMessageBox(error.toString(), _("Warning"), wxOK | wxICON_WARNING, this); else - wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR, this); } const bool startWatchingImmediately = loadCfgSuccess && !cfgFileName.empty(); @@ -102,30 +102,18 @@ MainDialog::~MainDialog() try //write config to XML { - writeRealConfig(currentCfg, lastConfigFileName()); + writeRealConfig(currentCfg, toZ(lastConfigFileName())); } catch (const xmlAccess::FfsXmlError& error) { - wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this); } } -void MainDialog::OnClose(wxCloseEvent& event) -{ - Destroy(); -} - - -void MainDialog::OnQuit(wxCommandEvent& event) -{ - Destroy(); -} - - const wxString& MainDialog::lastConfigFileName() { - static wxString instance = toWx(zen::getConfigDir()) + wxT("LastRun.ffs_real"); + static wxString instance = toWx(zen::getConfigDir()) + L"LastRun.ffs_real"; return instance; } @@ -145,23 +133,19 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event) //build information wxString build = __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode"); + build += L" - Unicode"; #else - build += wxT(" - ANSI"); + build += L" - ANSI"; #endif //wxUSE_UNICODE //compile time info about 32/64-bit build if (zen::is64BitBuild) - build += wxT(" x64"); + build += L" x64"; else - build += wxT(" x86"); + build += L" x86"; assert_static(zen::is32BitBuild || zen::is64BitBuild); - wxString buildFormatted = _("(Build: %x)"); - buildFormatted.Replace(wxT("%x"), build); - - wxMessageDialog* aboutDlg = new wxMessageDialog(this, wxString(L"RealtimeSync") + L"\n\n" + buildFormatted, _("About"), wxOK); - aboutDlg->ShowModal(); + wxMessageBox(L"RealtimeSync" L"\n\n" + replaceCpy(_("(Build: %x)"), L"%x", build), _("About"), wxOK, this); } @@ -170,7 +154,7 @@ void MainDialog::OnKeyPressed(wxKeyEvent& event) const int keyCode = event.GetKeyCode(); if (keyCode == WXK_ESCAPE) - Destroy(); + Close(); event.Skip(); } @@ -184,52 +168,43 @@ void MainDialog::OnStart(wxCommandEvent& event) switch (rts::startDirectoryMonitor(currentCfg, xmlAccess::extractJobName(currentConfigFileName))) { - case rts::QUIT: - { - Destroy(); + case rts::EXIT_APP: + Close(); return; - } - break; - case rts::RESUME: + case rts::SHOW_GUI: break; } - - Show(); + Show(); //don't show for EXIT_APP } void MainDialog::OnSaveConfig(wxCommandEvent& event) { - wxString defaultFileName = currentConfigFileName.empty() ? wxT("Realtime.ffs_real") : currentConfigFileName; + wxString defaultFileName = currentConfigFileName.empty() ? L"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 (defaultFileName.EndsWith(wxT(".ffs_batch"))) - defaultFileName.Replace(wxT(".ffs_batch"), wxT(".ffs_real"), false); + if (endsWith(defaultFileName, L".ffs_batch")) + replace(defaultFileName, L".ffs_batch", L".ffs_real", false); - wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("RealtimeSync configuration")) + wxT(" (*.ffs_real)|*.ffs_real"), wxFD_SAVE); - if (filePicker->ShowModal() == wxID_OK) - { - const wxString newFileName = filePicker->GetPath(); + wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, defaultFileName, + _("RealtimeSync configuration") + L" (*.ffs_real)|*.ffs_real", + wxFD_SAVE /*| wxFD_OVERWRITE_PROMPT*/); + if (filePicker.ShowModal() != wxID_OK) + return; - if (wxFileExists(newFileName)) - { - wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); - if (messageDlg->ShowModal() != wxID_OK) - return OnSaveConfig(event); //retry - } + const wxString newFileName = filePicker.GetPath(); - //write config to XML - const xmlAccess::XmlRealConfig currentCfg = getConfiguration(); - try - { - writeRealConfig(currentCfg, newFileName); - setLastUsedConfig(newFileName); - } - catch (const zen::FileError& error) - { - wxMessageBox(error.toString().c_str(), _("Error"), wxOK | wxICON_ERROR); - } + //write config to XML + const xmlAccess::XmlRealConfig currentCfg = getConfiguration(); + try + { + writeRealConfig(currentCfg, toZ(newFileName)); //throw FfsXmlError + setLastUsedConfig(newFileName); + } + catch (const xmlAccess::FfsXmlError& e) + { + wxMessageBox(e.toString().c_str(), _("Error"), wxOK | wxICON_ERROR, this); } } @@ -240,7 +215,7 @@ void MainDialog::loadConfig(const wxString& filename) try { - rts::readRealOrBatchConfig(filename, newConfig); + rts::readRealOrBatchConfig(toZ(filename), newConfig); } catch (const xmlAccess::FfsXmlError& error) { @@ -276,11 +251,11 @@ void MainDialog::setLastUsedConfig(const wxString& filename) void MainDialog::OnLoadConfig(wxCommandEvent& event) { - wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, wxEmptyString, - wxString(_("RealtimeSync configuration")) + wxT(" (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch"), - wxFD_OPEN); - if (filePicker->ShowModal() == wxID_OK) - loadConfig(filePicker->GetPath()); + wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, wxEmptyString, + _("RealtimeSync configuration") + L" (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch", + wxFD_OPEN); + if (filePicker.ShowModal() == wxID_OK) + loadConfig(filePicker.GetPath()); } @@ -342,13 +317,11 @@ void MainDialog::OnRemoveFolder(wxCommandEvent& event) //find folder pair originating the event const wxObject* const eventObj = event.GetEventObject(); for (std::vector<DirectoryPanel*>::const_iterator i = dirNamesExtra.begin(); i != dirNamesExtra.end(); ++i) - { if (eventObj == static_cast<wxObject*>((*i)->m_bpButtonRemoveFolder)) { removeAddFolder(i - dirNamesExtra.begin()); return; } - } } diff --git a/RealtimeSync/main_dlg.h b/RealtimeSync/main_dlg.h index 01789a45..edc66c47 100644 --- a/RealtimeSync/main_dlg.h +++ b/RealtimeSync/main_dlg.h @@ -44,17 +44,17 @@ public: void loadConfig(const wxString& filename); private: - virtual void OnClose( wxCloseEvent& event); - virtual void OnQuit( wxCommandEvent& event); - virtual void OnShowHelp( wxCommandEvent& event); - virtual void OnMenuAbout( wxCommandEvent& event); - virtual void OnAddFolder( wxCommandEvent& event); - virtual void OnRemoveFolder( wxCommandEvent& event); - virtual void OnRemoveTopFolder( wxCommandEvent& event); - virtual void OnKeyPressed( wxKeyEvent& event); - virtual void OnStart( wxCommandEvent& event); - virtual void OnSaveConfig( wxCommandEvent& event); - virtual void OnLoadConfig( wxCommandEvent& event); + virtual void OnClose (wxCloseEvent& event) { Destroy(); } + virtual void OnQuit (wxCommandEvent& event) { Destroy(); } + virtual void OnShowHelp (wxCommandEvent& event); + virtual void OnMenuAbout (wxCommandEvent& event); + virtual void OnAddFolder (wxCommandEvent& event); + virtual void OnRemoveFolder (wxCommandEvent& event); + virtual void OnRemoveTopFolder(wxCommandEvent& event); + virtual void OnKeyPressed (wxKeyEvent& event); + virtual void OnStart (wxCommandEvent& event); + virtual void OnSaveConfig (wxCommandEvent& event); + virtual void OnLoadConfig (wxCommandEvent& event); void setConfiguration(const xmlAccess::XmlRealConfig& cfg); xmlAccess::XmlRealConfig getConfiguration(); diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp index f81af50a..486aa8f1 100644 --- a/RealtimeSync/resources.cpp +++ b/RealtimeSync/resources.cpp @@ -23,7 +23,7 @@ const GlobalResources& GlobalResources::instance() GlobalResources::GlobalResources() { - wxFFileInputStream input(toWx(zen::getResourceDir()) + wxT("Resources.zip")); + wxFFileInputStream input(toWx(zen::getResourceDir()) + L"Resources.zip"); if (input.IsOk()) //if not... we don't want to react too harsh here { //activate support for .png files @@ -41,17 +41,17 @@ GlobalResources::GlobalResources() const wxString name = entry->GetName(); //generic image loading - if (name.EndsWith(wxT(".png"))) + if (endsWith(name, L".png")) bitmaps.insert(std::make_pair(name, wxImage(resourceFile, wxBITMAP_TYPE_PNG))); } } #ifdef FFS_WIN //for compatibility it seems we need to stick with a "real" icon - programIcon = wxIcon(wxT("A_PROGRAM_ICON")); + programIcon = wxIcon(L"A_PROGRAM_ICON"); #else //use big logo bitmap for better quality - programIcon.CopyFromBitmap(getImageInt(wxT("RealtimeSync.png"))); + programIcon.CopyFromBitmap(getImageInt(L"RealtimeSync.png")); #endif } @@ -59,8 +59,8 @@ GlobalResources::GlobalResources() const wxBitmap& GlobalResources::getImageInt(const wxString& name) const { - auto iter = bitmaps.find(name.Find(L'.') == wxNOT_FOUND ? //assume .png ending if nothing else specified - name + wxT(".png") : + auto iter = bitmaps.find(!contains(name, L'.') ? //assume .png ending if nothing else specified + name + L".png" : name); if (iter != bitmaps.end()) return iter->second; diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp index e18101e0..4afef5e4 100644 --- a/RealtimeSync/tray_menu.cpp +++ b/RealtimeSync/tray_menu.cpp @@ -16,38 +16,42 @@ #include <wx/menu.h> #include "watcher.h" #include <wx/utils.h> -#include <wx/log.h> #include <wx/icon.h> //Linux needs this #include <wx/timer.h> +#include <wx+/mouse_move_dlg.h> #include "resources.h" #include <wx+/string_conv.h> #include <zen/assert_static.h> #include <zen/build_info.h> #include <wx+/shell_execute.h> +#include "gui_generated.h" using namespace rts; using namespace zen; -class TrayIconHolder : private wxEvtHandler + +namespace { -public: - TrayIconHolder(const wxString& jobname); - ~TrayIconHolder(); +struct AbortCallback //never throw exceptions through a C-Layer (GUI)! +{ + virtual ~AbortCallback() {} + virtual void requestResume() = 0; + virtual void requestAbort() = 0; +}; - void doUiRefreshNow(); - void showIconActive(); - void showIconWaiting(); - void requestAbort() +//RtsTrayIcon is a dumb class whose sole purpose is to enable wxWidgets deferred deletion +class RtsTrayIconRaw : public wxTaskBarIcon +{ +public: + RtsTrayIconRaw(AbortCallback& abortCb) : abortCb_(&abortCb) { - m_abortRequested = true; + Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIconRaw::OnDoubleClick), nullptr, this); } - void OnRequestResume(wxCommandEvent& event) - { - m_resumeRequested = true; - } + void dontCallBackAnymore() { abortCb_ = nullptr; } //call before tray icon is marked for deferred deletion +private: enum Selection { CONTEXT_ABORT, @@ -55,34 +59,9 @@ public: CONTEXT_ABOUT }; - void OnContextMenuSelection(wxCommandEvent& event); - -private: - class RtsTrayIcon; - RtsTrayIcon* trayMenu; - - bool m_abortRequested; - bool m_resumeRequested; - - const wxString jobName_; //RTS job name, may be empty -}; - - -//RtsTrayIcon shall be a dumb class whose sole purpose is to enable wxWidgets deferred deletion -class TrayIconHolder::RtsTrayIcon : public wxTaskBarIcon -{ -public: - RtsTrayIcon(TrayIconHolder* parent) : parent_(parent) {} - - void parentHasDied() //call before tray icon is marked for deferred deletion - { - parent_ = nullptr; - } - -private: virtual wxMenu* CreatePopupMenu() { - if (!parent_) + if (!abortCb_) return nullptr; wxMenu* contextMenu = new wxMenu; @@ -91,169 +70,150 @@ private: contextMenu->AppendSeparator(); contextMenu->Append(CONTEXT_ABORT, _("&Exit")); //event handling - contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TrayIconHolder::OnContextMenuSelection), nullptr, parent_); + contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RtsTrayIconRaw::OnContextMenuSelection), nullptr, this); return contextMenu; //ownership transferred to caller } - TrayIconHolder* parent_; -}; -//############################################################################################################## + void OnContextMenuSelection(wxCommandEvent& event) + { + if (!abortCb_) + return; + switch (static_cast<Selection>(event.GetId())) + { + case CONTEXT_ABORT: + abortCb_->requestAbort(); + break; -class AbortThisProcess //exception class -{ -public: - AbortThisProcess(MonitorResponse command) : command_(command) {} + case CONTEXT_RESTORE: + abortCb_->requestResume(); + break; + + case CONTEXT_ABOUT: + { + //build information + wxString build = __TDATE__; +#if wxUSE_UNICODE + build += L" - Unicode"; +#else + build += L" - ANSI"; +#endif //wxUSE_UNICODE + + //compile time info about 32/64-bit build + if (zen::is64BitBuild) + build += L" x64"; + else + build += L" x86"; + assert_static(zen::is32BitBuild || zen::is64BitBuild); + + wxMessageBox(L"RealtimeSync" L"\n\n" + replaceCpy(_("(Build: %x)"), L"%x", build), _("About"), wxOK); + } + break; + } + } - MonitorResponse getCommand() const + void OnDoubleClick(wxCommandEvent& event) { - return command_; + if (abortCb_) + abortCb_->requestResume(); } -private: - MonitorResponse command_; + AbortCallback* abortCb_; }; -//############################################################################################################## -TrayIconHolder::TrayIconHolder(const wxString& jobname) : - m_abortRequested(false), - m_resumeRequested(false), - jobName_(jobname) +class TrayIconHolder { - trayMenu = new RtsTrayIcon(this); //not in initialization list: give it a valid parent object! - - showIconActive(); - - //register double-click - trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), nullptr, this); -} - +public: + TrayIconHolder(const wxString& jobname, AbortCallback& abortCb) : + jobName_(jobname) + { + trayMenu = new RtsTrayIconRaw(abortCb); //not in initialization list: give it a valid parent object! + showIconActive(); + } -TrayIconHolder::~TrayIconHolder() -{ - trayMenu->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(TrayIconHolder::OnRequestResume), nullptr, this); - trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place - trayMenu->parentHasDied(); + ~TrayIconHolder() + { + trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place + trayMenu->dontCallBackAnymore(); - //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); -} + //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); + } + void doUiRefreshNow() + { + wxTheApp->Yield(); + } //yield is UI-layer which is represented by this tray icon -void TrayIconHolder::showIconActive() -{ - wxIcon realtimeIcon; + void showIconActive() + { + wxIcon realtimeIcon; #ifdef FFS_WIN - realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_win.png"))); //use a 16x16 bitmap + realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_win.png")); //use a 16x16 bitmap #elif defined FFS_LINUX - realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit + realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_linux.png")); //use a 22x22 bitmap for perfect fit #endif - const wxString postFix = jobName_.empty() ? wxString() : (wxT("\n\"") + jobName_ + wxT("\"")); - trayMenu->SetIcon(realtimeIcon, _("Monitoring active...") + postFix); -} - + const wxString postFix = jobName_.empty() ? wxString() : (L"\n\"" + jobName_ + L"\""); + trayMenu->SetIcon(realtimeIcon, _("Monitoring active...") + postFix); + } -void TrayIconHolder::showIconWaiting() -{ - wxIcon realtimeIcon; + void showIconWaiting() + { + wxIcon realtimeIcon; #ifdef FFS_WIN - realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_waiting_win.png"))); //use a 16x16 bitmap + realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_waiting_win.png")); //use a 16x16 bitmap #elif defined FFS_LINUX - realtimeIcon.CopyFromBitmap(GlobalResources::getImage(wxT("RTS_tray_waiting_linux.png"))); //use a 22x22 bitmap for perfect fit + realtimeIcon.CopyFromBitmap(GlobalResources::getImage(L"RTS_tray_waiting_linux.png")); //use a 22x22 bitmap for perfect fit #endif - const wxString postFix = jobName_.empty() ? wxString() : (wxT("\n\"") + jobName_ + wxT("\"")); - trayMenu->SetIcon(realtimeIcon, _("Waiting for missing directories...") + postFix); -} - - -void TrayIconHolder::OnContextMenuSelection(wxCommandEvent& event) -{ - const int eventId = event.GetId(); - switch (static_cast<Selection>(eventId)) - { - case CONTEXT_ABORT: - requestAbort(); - break; - case CONTEXT_RESTORE: - OnRequestResume(event); //just remember: never throw exceptions through a C-Layer (GUI) ;) - break; - case CONTEXT_ABOUT: - { - //build information - wxString build = __TDATE__; -#if wxUSE_UNICODE - build += wxT(" - Unicode"); -#else - build += wxT(" - ANSI"); -#endif //wxUSE_UNICODE - - //compile time info about 32/64-bit build - if (zen::is64BitBuild) - build += wxT(" x64"); - else - build += wxT(" x86"); - assert_static(zen::is32BitBuild || zen::is64BitBuild); - - wxString buildFormatted = _("(Build: %x)"); - buildFormatted.Replace(wxT("%x"), build); - - wxMessageDialog aboutDlg(nullptr, wxString(wxT("RealtimeSync")) + wxT("\n\n") + buildFormatted, _("About"), wxOK); - aboutDlg.ShowModal(); - } - break; + const wxString postFix = jobName_.empty() ? wxString() : (L"\n\"" + jobName_ + L"\""); + trayMenu->SetIcon(realtimeIcon, _("Waiting for missing directories...") + postFix); } -} - -void TrayIconHolder::doUiRefreshNow() -{ - wxTheApp->Yield(); +private: + RtsTrayIconRaw* trayMenu; + const wxString jobName_; //RTS job name, may be empty +}; - if (m_abortRequested) - throw ::AbortThisProcess(QUIT); - if (m_resumeRequested) - throw ::AbortThisProcess(RESUME); -} //############################################################################################################## -namespace -{ -std::vector<Zstring> convert(const std::vector<wxString>& dirList) +struct AbortMonitoring//exception class { - std::set<Zstring, LessFilename> output; - std::transform(dirList.begin(), dirList.end(), - std::inserter(output, output.end()), [](const wxString & str) { return zen::toZ(str); }); - return std::vector<Zstring>(output.begin(), output.end()); -} -} - + AbortMonitoring(AbortReason reasonCode) : reasonCode_(reasonCode) {} + AbortReason reasonCode_; +}; class StartSyncNowException {}; +//############################################################################################################## -class WaitCallbackImpl : public rts::WaitCallback +class WaitCallbackImpl : public rts::WaitCallback, private AbortCallback { public: WaitCallbackImpl(const wxString& jobname) : - trayIcon(jobname), - nextSyncStart_(std::numeric_limits<long>::max()) {} + trayIcon(jobname, *this), + nextSyncStart_(std::numeric_limits<long>::max()), + resumeRequested(false), + abortRequested(false) {} - void notifyAllDirectoriesExist() - { - trayIcon.showIconActive(); - } + void notifyAllDirectoriesExist() { trayIcon.showIconActive(); } + void notifyDirectoryMissing () { trayIcon.showIconWaiting(); } - void notifyDirectoryMissing() - { - trayIcon.showIconWaiting(); - } + void scheduleNextSync(long nextSyncStart) { nextSyncStart_ = nextSyncStart; } + void clearSchedule() { nextSyncStart_ = std::numeric_limits<long>::max(); } - virtual void requestUiRefresh() //throw StartSyncNowException() + //implement WaitCallback + virtual void requestUiRefresh() //throw StartSyncNowException, AbortMonitoring { + if (resumeRequested) + throw AbortMonitoring(SHOW_GUI); + + if (abortRequested) + throw AbortMonitoring(EXIT_APP); + if (nextSyncStart_ <= wxGetLocalTime()) throw StartSyncNowException(); //abort wait and start sync @@ -261,16 +221,87 @@ public: trayIcon.doUiRefreshNow(); } - void scheduleNextSync(long nextSyncStart) +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; +}; + + + +class ErrorDlgWithTimeout : public ErrorDlgGenerated +{ +public: + ErrorDlgWithTimeout(wxWindow* parent, const wxString& messageText) : + ErrorDlgGenerated(parent), + secondsLeft(15) //give user some time to read msg!? { - nextSyncStart_ = nextSyncStart; +#ifdef FFS_WIN + new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this" +#endif + m_bitmap10->SetBitmap(GlobalResources::getImage(L"error")); + m_textCtrl8->SetValue(messageText); + m_buttonRetry->SetFocus(); + + //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(); } + enum ButtonPressed + { + BUTTON_RETRY, + BUTTON_ABORT + }; + private: - TrayIconHolder trayIcon; - long nextSyncStart_; + void OnTimerEvent(wxEvent& event) + { + --secondsLeft; + if (secondsLeft < 0) + { + EndModal(BUTTON_RETRY); + return; + } + updateButtonLabel(); + } + + void updateButtonLabel() + { + m_buttonRetry->SetLabel(_("&Retry") + L" (" + replaceCpy(_P("1 sec", "%x sec", secondsLeft), L"%x", numberTo<std::wstring>(secondsLeft)) + L")"); + Layout(); + } + + void OnClose(wxCloseEvent& event) { EndModal(BUTTON_ABORT); } + void OnRetry(wxCommandEvent& event) { EndModal(BUTTON_RETRY); } + void OnAbort(wxCommandEvent& event) { EndModal(BUTTON_ABORT); } + + int secondsLeft; + wxTimer timer; }; + +bool reportErrorTimeout(const std::wstring& msg) //return true if timeout or user selected "retry", else abort +{ + ErrorDlgWithTimeout errorDlg(nullptr, msg); + //errorDlg.Raise(); -> don't steal focus every X seconds + switch (static_cast<ErrorDlgWithTimeout::ButtonPressed>(errorDlg.ShowModal())) + { + case ErrorDlgWithTimeout::BUTTON_RETRY: + return true; + case ErrorDlgWithTimeout::BUTTON_ABORT: + return false; + } + return false; +} +} + /* Data Flow: ---------- @@ -278,82 +309,96 @@ Data Flow: TrayIconHolder (GUI output) /|\ | -WaitCallbackImpl (higher level "interface") +WaitCallbackImpl /|\ | startDirectoryMonitor() (wire dir-changes and execution of commandline) - /|\ - | -watcher.h (low level wait for directory changes) */ -rts::MonitorResponse rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname) +rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname) { - Zstring lastFileChanged; + const std::vector<Zstring> dirList = toZ(config.directories); + + auto cmdLine = config.commandline; + trim(cmdLine); + + if (cmdLine.empty()) + { + wxMessageBox(replaceCpy(_("Invalid command line: %x"), L"%x", L"\"\""), _("Error"), wxOK | wxICON_ERROR); + return SHOW_GUI; + } + if (dirList.empty() || std::any_of(dirList.begin(), dirList.end(), [](Zstring str) -> bool { trim(str); return str.empty(); })) + { + wxMessageBox(_("A directory input field is empty."), _("Error"), wxOK | wxICON_ERROR); + return SHOW_GUI; + } - const std::vector<Zstring> dirList = convert(config.directories); try { + Zstring lastFileChanged; WaitCallbackImpl callback(jobname); - if (config.commandline.empty()) - { - std::wstring errorMsg = _("Invalid command line: %x"); - replace(errorMsg, L"%x", L"\"" + config.commandline + L"\""); - throw FileError(errorMsg); - } - - callback.notifyDirectoryMissing(); - waitForMissingDirs(dirList, &callback); - callback.notifyAllDirectoriesExist(); - - while (true) + auto execMonitoring = [&] //throw FileError, AbortMonitoring { - ::wxSetEnv(L"changed_file", utf8CvrtTo<wxString>(lastFileChanged)); //some way to output what file changed to the user - lastFileChanged.clear(); //make sure old name is not shown again after a directory reappears - - //execute command - zen::shellExecute(config.commandline, zen::EXEC_TYPE_SYNC); + callback.clearSchedule(); - wxLog::FlushActive(); //show wxWidgets error messages (if any) + callback.notifyDirectoryMissing(); + waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring + callback.notifyAllDirectoriesExist(); - callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet) + //schedule initial execution only AFTER waitForMissingDirs(), else StartSyncNowException might be thrown while directory checking hangs + callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay)); - try + while (true) { - while (true) + try { - //wait for changes (and for all directories to become available) - WaitResult res = waitForChanges(dirList, &callback); - switch (res.type) + while (true) { - case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available! - callback.scheduleNextSync(std::numeric_limits<long>::max()); //next sync not scheduled (yet) - callback.notifyDirectoryMissing(); - waitForMissingDirs(dirList, &callback); - callback.notifyAllDirectoriesExist(); - break; - case CHANGE_DETECTED: - lastFileChanged = res.filename; - break; + //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.clearSchedule(); + + callback.notifyDirectoryMissing(); + waitForMissingDirs(dirList, callback); //throw FileError, StartSyncNowException(not scheduled yet), AbortMonitoring + callback.notifyAllDirectoriesExist(); + break; + + case CHANGE_DETECTED: + lastFileChanged = res.filename; + break; + } + callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay)); } - - callback.scheduleNextSync(wxGetLocalTime() + static_cast<long>(config.delay)); } + catch (StartSyncNowException&) {} + + ::wxSetEnv(L"changed_file", utf8CvrtTo<wxString>(lastFileChanged)); //some way to output what file changed to the user + lastFileChanged.clear(); //make sure old name is not shown again after a directory reappears + + //execute command + zen::shellExecute(cmdLine, zen::EXEC_TYPE_SYNC); + callback.clearSchedule(); + } + }; + + 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; } - catch (StartSyncNowException&) {} - } - } - catch (const ::AbortThisProcess& ab) - { - return ab.getCommand(); } - catch (const zen::FileError& error) + catch (const AbortMonitoring& ab) { - wxMessageBox(error.toString(), _("Error"), wxOK | wxICON_ERROR); - return RESUME; + return ab.reasonCode_; } - - return RESUME; } diff --git a/RealtimeSync/tray_menu.h b/RealtimeSync/tray_menu.h index 21d26932..9c910694 100644 --- a/RealtimeSync/tray_menu.h +++ b/RealtimeSync/tray_menu.h @@ -13,13 +13,12 @@ namespace rts { -enum MonitorResponse +enum AbortReason { - RESUME, - QUIT + SHOW_GUI, + EXIT_APP }; - -MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty +AbortReason startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty } diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 36ceb006..ee56bc7c 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -5,30 +5,31 @@ // ************************************************************************** #include "watcher.h" +#include <set> +#include <zen/tick_count.h> #include <zen/file_handling.h> #include <zen/stl_tools.h> -#include <set> -#include <ctime> -#include <wx/timer.h> -#include "../lib/resolve_path.h" #include <zen/dir_watcher.h> -#include <wx+/string_conv.h> #include <zen/thread.h> +#include <zen/assert_static.h> +#include <wx+/string_conv.h> +#include <wx/timer.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 -#include <wx/msgdlg.h> using namespace zen; +namespace +{ +const std::int64_t TICKS_UPDATE_INTERVAL = rts::UI_UPDATE_INTERVAL* ticksPerSec() / 1000; +TickVal lastExec = getTicks(); +}; bool rts::updateUiIsAllowed() { - const std::clock_t CLOCK_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * CLOCKS_PER_SEC / 1000; - - static std::clock_t lastExec = 0; - const std::clock_t now = std::clock(); //this is quite fast: 2 * 10^-5 - - if (now - lastExec >= CLOCK_UPDATE_INTERVAL) //perform ui updates not more often than necessary + const TickVal now = getTicks(); //0 on error + if (now - lastExec >= TICKS_UPDATE_INTERVAL) //perform ui updates not more often than necessary { lastExec = now; return true; @@ -36,29 +37,30 @@ bool rts::updateUiIsAllowed() return false; } + namespace { const int CHECK_DIR_INTERVAL = 1000; //1 second interval -} -rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError +std::vector<Zstring> getFormattedDirs(const std::vector<Zstring>& dirs) //throw FileError { - std::set<Zstring, LessFilename> dirNamesFmt; + std::set<Zstring, LessFilename> tmp; //make unique - std::for_each(dirNamesNonFmt.begin(), dirNamesNonFmt.end(), - [&](const Zstring& dirnameNonFmt) - { - const Zstring& dirnameFmt = zen::getFormattedDirectoryName(dirnameNonFmt); + std::transform(dirs.begin(), dirs.end(), std::inserter(tmp, tmp.end()), + [](const Zstring& dirnameNonFmt) { return getFormattedDirectoryName(dirnameNonFmt); }); - if (dirnameFmt.empty()) - throw zen::FileError(_("A directory input field is empty.")); - dirNamesFmt.insert(dirnameFmt); - }); - if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless - throw zen::FileError(_("A directory input field is empty.")); + return std::vector<Zstring>(tmp.begin(), tmp.end()); +} +} +rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError +{ + const std::vector<Zstring> dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError + if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless + throw zen::FileError(_("A directory input field is empty.")); //should have been checked by caller! + //detect when volumes are removed/are not available anymore std::vector<std::pair<Zstring, std::shared_ptr<DirWatcher>>> watches; @@ -67,16 +69,24 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, const Zstring& dirnameFmt = *iter; try { + //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))) + statusHandler.requestUiRefresh(); //may throw! + if (!ftDirExists.get()) + return WaitResult(CHANGE_DIR_MISSING, dirnameFmt); + + watches.push_back(std::make_pair(dirnameFmt, std::make_shared<DirWatcher>(dirnameFmt))); //throw FileError, ErrorNotExisting } catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!! { - return CHANGE_DIR_MISSING; + return WaitResult(CHANGE_DIR_MISSING, dirnameFmt); } catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing) { - if (!dirExists(dirnameFmt)) //not an atomic behavior!!! - return CHANGE_DIR_MISSING; + if (!dirExists(dirnameFmt)) //file system race condition!! + return WaitResult(CHANGE_DIR_MISSING, dirnameFmt); throw; } } @@ -104,11 +114,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 - return CHANGE_DIR_MISSING; + return WaitResult(CHANGE_DIR_MISSING, dirname); try { - std::vector<Zstring> changedFiles = watcher.getChanges([&] { statusHandler->requestUiRefresh(); }); //throw FileError, ErrorNotExisting + std::vector<Zstring> changedFiles = watcher.getChanges([&] { statusHandler.requestUiRefresh(); }); //throw FileError, ErrorNotExisting //remove to be ignored changes vector_remove_if(changedFiles, [](const Zstring& name) @@ -130,67 +140,61 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, } catch (ErrorNotExisting&) //nice atomic behavior: *no* second directory existence check!!! { - return CHANGE_DIR_MISSING; + return WaitResult(CHANGE_DIR_MISSING, dirname); } catch (FileError&) //play safe: remedy potential FileErrors that should have been ErrorNotExisting (e.g. Linux: errors during directory traversing) { - if (!dirExists(dirname)) //not an atomic behavior!!! - return CHANGE_DIR_MISSING; + if (!dirExists(dirname)) //file system race condition!! + return WaitResult(CHANGE_DIR_MISSING, dirname); throw; } } - wxMilliSleep(rts::UI_UPDATE_INTERVAL); - statusHandler->requestUiRefresh(); + boost::this_thread::sleep(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL)); + statusHandler.requestUiRefresh(); } } //support for monitoring newly connected directories volumes (e.g.: USB-sticks) -void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback* statusHandler) //throw FileError +void rts::waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, WaitCallback& statusHandler) //throw FileError { - wxLongLong lastCheck; - while (true) { - const wxLongLong current = wxGetLocalTimeMillis(); - if (current - lastCheck >= CHECK_DIR_INTERVAL) - { - lastCheck = current; + //support specifying volume by name => call getFormattedDirectoryName() repeatedly + const std::vector<Zstring>& dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError - auto ftDirMissing = async([=]() -> bool + bool allExisting = true; + for (auto iter = dirNamesFmt.begin(); iter != dirNamesFmt.end(); ++iter) + { + const Zstring dirnameFmt = *iter; + auto ftDirExisting = async([=]() -> bool { - return std::find_if(dirNamesNonFmt.begin(), dirNamesNonFmt.end(), - [](const Zstring& dirnameNonFmt) -> bool - { - //support specifying volume by name => call getFormattedDirectoryName() repeatedly - const Zstring dirnameFmt = zen::getFormattedDirectoryName(dirnameNonFmt); - - if (dirnameFmt.empty()) - throw zen::FileError(_("A directory input field is empty.")); #ifdef FFS_WIN - //1. login to network share, if necessary - loginNetworkShare(dirnameFmt, false); //login networks shares, no PW prompt -> is this really RTS's task? + //1. login to network share, if necessary -> we probably do NOT want multiple concurrent runs: GUI!? + loginNetworkShare(dirnameFmt, false); //login networks shares, no PW prompt -> is this really RTS's job? #endif - //2. check dir existence - return !zen::dirExists(dirnameFmt); - }) != dirNamesNonFmt.end(); + //2. check dir existence + return zen::dirExists(dirnameFmt); }); - while (!ftDirMissing.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL))) - statusHandler->requestUiRefresh(); //may throw! + while (!ftDirExisting.timed_wait(boost::posix_time::milliseconds(rts::UI_UPDATE_INTERVAL))) + statusHandler.requestUiRefresh(); //may throw! - try + if (!ftDirExisting.get()) { - if (!ftDirMissing.get()) //throw X - return; - } - catch (...) //boost::future seems to map async exceptions to "some" boost exception type -> migrate this for C++11 - { - throw zen::FileError(_("A directory input field is empty.")); + allExisting = false; + break; } } + if (allExisting) + return; - wxMilliSleep(rts::UI_UPDATE_INTERVAL); - statusHandler->requestUiRefresh(); + //wait some time... + assert_static(CHECK_DIR_INTERVAL % UI_UPDATE_INTERVAL == 0); + for (int i = 0; i < CHECK_DIR_INTERVAL / UI_UPDATE_INTERVAL; ++i) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)); + statusHandler.requestUiRefresh(); + } } } diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h index cb39ed20..17252535 100644 --- a/RealtimeSync/watcher.h +++ b/RealtimeSync/watcher.h @@ -14,8 +14,7 @@ namespace rts { -const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss - +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(); @@ -33,19 +32,22 @@ enum ChangeType CHANGE_DETECTED, CHANGE_DIR_MISSING }; + struct WaitResult { - WaitResult(ChangeType tp, const Zstring& chgFile = Zstring()) : type(tp), filename(chgFile) {} + WaitResult(ChangeType tp, const Zstring& chgFile) : type(tp), filename(chgFile) {} ChangeType type; - Zstring filename; //filled if type == CHANGE_DETECTED + Zstring filename; //file or directory name }; -WaitResult waitForChanges(const std::vector<Zstring>& dirNamesNonFmt, //non-formatted dir names that yet require call to getFormattedDirectoryName() - WaitCallback* statusHandler); //throw(FileError) + +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) void waitForMissingDirs(const std::vector<Zstring>& dirNamesNonFmt, - WaitCallback* statusHandler); //throw(FileError) + WaitCallback& statusHandler); //throw FileError } #endif // WATCHER_H_INCLUDED diff --git a/RealtimeSync/xml_ffs.cpp b/RealtimeSync/xml_ffs.cpp index 6ec5f843..6572800b 100644 --- a/RealtimeSync/xml_ffs.cpp +++ b/RealtimeSync/xml_ffs.cpp @@ -46,7 +46,7 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat } -void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config) //throw xmlAccess::FfsXmlError; +void rts::readRealOrBatchConfig(const Zstring& filename, xmlAccess::XmlRealConfig& config) //throw xmlAccess::FfsXmlError; { if (xmlAccess::getXmlType(filename) != xmlAccess::XML_TYPE_BATCH) { @@ -63,11 +63,11 @@ void rts::readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConf catch (const xmlAccess::FfsXmlError& e) { if (e.getSeverity() == xmlAccess::FfsXmlError::WARNING) - config = convertBatchToReal(batchCfg, toZ(filename)); //do work despite parsing errors, then re-throw + config = convertBatchToReal(batchCfg, filename); //do work despite parsing errors, then re-throw throw; // } - config = convertBatchToReal(batchCfg, toZ(filename)); + config = convertBatchToReal(batchCfg, filename); } diff --git a/RealtimeSync/xml_ffs.h b/RealtimeSync/xml_ffs.h index abff3c10..b63c3620 100644 --- a/RealtimeSync/xml_ffs.h +++ b/RealtimeSync/xml_ffs.h @@ -8,13 +8,14 @@ #define XMLFREEFILESYNC_H_INCLUDED #include "xml_proc.h" +#include <zen/zstring.h> //reuse (some of) FreeFileSync's xml files namespace rts { -void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::FfsXmlError); +void readRealOrBatchConfig(const Zstring& filename, xmlAccess::XmlRealConfig& config); //throw FfsXmlError int getProgramLanguage(); } diff --git a/RealtimeSync/xml_proc.cpp b/RealtimeSync/xml_proc.cpp index 4f9306d2..891cb2df 100644 --- a/RealtimeSync/xml_proc.cpp +++ b/RealtimeSync/xml_proc.cpp @@ -36,22 +36,22 @@ bool isXmlTypeRTS(const XmlDoc& doc) //throw() } -void xmlAccess::readRealConfig(const wxString& filename, XmlRealConfig& config) +void xmlAccess::readRealConfig(const Zstring& filename, XmlRealConfig& config) { - if (!fileExists(toZ(filename))) - throw FfsXmlError(_("File does not exist:") + L"\n\"" + toZ(filename) + L"\""); + if (!fileExists(filename)) + throw FfsXmlError(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename))); XmlDoc doc; - loadXmlDocument(toZ(filename), doc); //throw (FfsXmlError) + loadXmlDocument(filename, doc); //throw FfsXmlError if (!isXmlTypeRTS(doc)) - throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + toZ(filename) + L"\""); + throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename))); XmlIn in(doc); ::readConfig(in, config); if (in.errorsOccured()) - throw FfsXmlError(_("Configuration loaded partially only:") + L"\n\"" + toZ(filename) + L"\"\n\n" + + throw FfsXmlError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" + getErrorMessageFormatted(in), FfsXmlError::WARNING); } @@ -67,7 +67,7 @@ void writeConfig(const XmlRealConfig& config, XmlOut& out) } -void xmlAccess::writeRealConfig(const XmlRealConfig& config, const wxString& filename) +void xmlAccess::writeRealConfig(const XmlRealConfig& config, const Zstring& filename) { XmlDoc doc("FreeFileSync"); doc.root().setAttribute("XmlType", "REAL"); @@ -75,5 +75,5 @@ void xmlAccess::writeRealConfig(const XmlRealConfig& config, const wxString& fil XmlOut out(doc); writeConfig(config, out); - saveXmlDocument(doc, toZ(filename)); //throw (FfsXmlError) + saveXmlDocument(doc, filename); //throw (FfsXmlError) } diff --git a/RealtimeSync/xml_proc.h b/RealtimeSync/xml_proc.h index a2e178d4..e07f9844 100644 --- a/RealtimeSync/xml_proc.h +++ b/RealtimeSync/xml_proc.h @@ -9,6 +9,7 @@ #include <vector> #include <wx/string.h> +#include <zen/zstring.h> #include "../lib/xml_base.h" @@ -22,8 +23,8 @@ struct XmlRealConfig size_t delay; }; -void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::FfsXmlError); -void writeRealConfig(const XmlRealConfig& config, const wxString& filename); //throw (xmlAccess::FfsXmlError); +void readRealConfig(const Zstring& filename, XmlRealConfig& config); //throw FfsXmlError +void writeRealConfig(const XmlRealConfig& config, const Zstring& filename); //throw FfsXmlError } #endif // XMLPROCESSING_H_INCLUDED |