diff options
Diffstat (limited to 'RealtimeSync')
-rw-r--r-- | RealtimeSync/RealtimeSync.cbp | 4 | ||||
-rw-r--r-- | RealtimeSync/RealtimeSync.vcproj | 33 | ||||
-rw-r--r-- | RealtimeSync/RealtimeSync.xpm | 312 | ||||
-rw-r--r-- | RealtimeSync/application.cpp | 28 | ||||
-rw-r--r-- | RealtimeSync/application.h | 4 | ||||
-rw-r--r-- | RealtimeSync/functions.h | 2 | ||||
-rw-r--r-- | RealtimeSync/guiGenerated.cpp | 38 | ||||
-rw-r--r-- | RealtimeSync/guiGenerated.h | 9 | ||||
-rw-r--r-- | RealtimeSync/mainDialog.cpp | 32 | ||||
-rw-r--r-- | RealtimeSync/mainDialog.h | 6 | ||||
-rw-r--r-- | RealtimeSync/resources.cpp | 27 | ||||
-rw-r--r-- | RealtimeSync/resources.h | 4 | ||||
-rw-r--r-- | RealtimeSync/trayMenu.cpp | 23 | ||||
-rw-r--r-- | RealtimeSync/trayMenu.h | 12 | ||||
-rw-r--r-- | RealtimeSync/watcher.cpp | 335 | ||||
-rw-r--r-- | RealtimeSync/watcher.h | 16 | ||||
-rw-r--r-- | RealtimeSync/xmlFreeFileSync.h | 4 | ||||
-rw-r--r-- | RealtimeSync/xmlProcessing.h | 18 |
18 files changed, 472 insertions, 435 deletions
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index d15a5ab2..76eccb5e 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -128,11 +128,15 @@ <Unit filename="..\shared\fileError.h" /> <Unit filename="..\shared\fileHandling.cpp" /> <Unit filename="..\shared\fileHandling.h" /> + <Unit filename="..\shared\fileID.cpp" /> <Unit filename="..\shared\fileTraverser.cpp" /> <Unit filename="..\shared\globalFunctions.cpp" /> <Unit filename="..\shared\globalFunctions.h" /> <Unit filename="..\shared\localization.cpp" /> <Unit filename="..\shared\localization.h" /> + <Unit filename="..\shared\longPathPrefix.cpp" /> + <Unit filename="..\shared\longPathPrefix.h" /> + <Unit filename="..\shared\recycler.cpp" /> <Unit filename="..\shared\shadow.cpp" /> <Unit filename="..\shared\standardPaths.cpp" /> <Unit filename="..\shared\standardPaths.h" /> diff --git a/RealtimeSync/RealtimeSync.vcproj b/RealtimeSync/RealtimeSync.vcproj index f3501a17..ddf293ea 100644 --- a/RealtimeSync/RealtimeSync.vcproj +++ b/RealtimeSync/RealtimeSync.vcproj @@ -69,7 +69,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateManifest="true" @@ -129,7 +129,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";..\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud";..\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;__WXDEBUG__;TIXML_USE_STL;ZSTRING_WIDE_CHAR" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -145,7 +145,7 @@ <Tool Name="VCResourceCompilerTool" Culture="0" - AdditionalIncludeDirectories="D:\Programme\C++\wxWidgets-x64\include;D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" + AdditionalIncludeDirectories="C:\Programme\C++\wxWidgets-x64\include;C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswud" /> <Tool Name="VCPreLinkEventTool" @@ -153,9 +153,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28ud_adv.lib 
wxmsw28ud_core.lib 
wxbase28ud.lib 
wxpngd.lib
 wxzlibd.lib 
wxbase28ud_net.lib comctl32.lib ws2_32.lib Rpcrt4.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="2" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateManifest="true" GenerateDebugInformation="true" SubSystem="2" @@ -237,7 +237,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets\lib\vc_lib" GenerateDebugInformation="false" @@ -298,12 +298,13 @@ Optimization="2" EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";..\shared\boost_1_x" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu";..\shared\boost_1_x" PreprocessorDefinitions="wxUSE_UNICODE;__WXMSW__;FFS_WIN;NDEBUG;TIXML_USE_STL;ZSTRING_WIDE_CHAR" RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="3" + SuppressStartupBanner="false" DebugInformationFormat="3" DisableSpecificWarnings="4804" /> @@ -313,7 +314,7 @@ <Tool Name="VCResourceCompilerTool" Culture="1033" - AdditionalIncludeDirectories=""D:\Programme\C++\wxWidgets-x64\include";"D:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" + AdditionalIncludeDirectories=""C:\Programme\C++\wxWidgets-x64\include";"C:\Programme\C++\wxWidgets-x64\lib\vc_lib\mswu"" /> <Tool Name="VCPreLinkEventTool" @@ -321,9 +322,9 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="wxmsw28u_adv.lib 
wxmsw28u_core.lib 
wxbase28u.lib 
wxpng.lib 
wxzlib.lib 
wxbase28u_net.lib comctl32.lib ws2_32.lib" - OutputFile="..\BUILD\$(ProjectName).exe" + OutputFile="..\BUILD\$(ProjectName)_$(PlatformName).exe" LinkIncremental="1" - AdditionalLibraryDirectories="D:\Programme\C++\wxWidgets-x64\lib\vc_lib" + AdditionalLibraryDirectories="C:\Programme\C++\wxWidgets-x64\lib\vc_lib" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" @@ -383,6 +384,10 @@ > </File> <File + RelativePath="..\shared\fileID.cpp" + > + </File> + <File RelativePath="..\shared\fileTraverser.cpp" > </File> @@ -403,6 +408,10 @@ > </File> <File + RelativePath="..\shared\longPathPrefix.cpp" + > + </File> + <File RelativePath=".\mainDialog.cpp" > </File> @@ -411,6 +420,10 @@ > </File> <File + RelativePath="..\shared\recycler.cpp" + > + </File> + <File RelativePath=".\resources.cpp" > </File> diff --git a/RealtimeSync/RealtimeSync.xpm b/RealtimeSync/RealtimeSync.xpm deleted file mode 100644 index 557ef973..00000000 --- a/RealtimeSync/RealtimeSync.xpm +++ /dev/null @@ -1,312 +0,0 @@ -/* XPM */ -static const char* RealtimeSync_xpm[] = { -"32 32 277 2", -" c None", -"! c black", -"# c #2A0404", -"$ c #330505", -"% c #3D0707", -"& c #360606", -"' c #340606", -"( c #500909", -") c #630B0B", -"* c #890F0F", -"+ c #AC1414", -", c #AB1414", -"- c #9F1212", -". c #820F0F", -"0 c #510909", -"1 c #2F0505", -"2 c #530A0A", -"3 c #8B1010", -"4 c #E83E3E", -"5 c #F39494", -"6 c #F6ADAD", -"7 c #F49B9B", -"8 c #F07E7E", -"9 c #EC5C5C", -": c #E73636", -"; c #D71818", -"< c #AD1414", -"= c #7C0E0E", -"> c #410707", -"? c #E73232", -"@ c #FACECE", -"A c #FCDFDF", -"B c #F7B8B8", -"C c #F39090", -"D c #EF6E6E", -"E c #EA4D4D", -"F c #E72D2D", -"G c #E41E1E", -"H c #E31F1F", -"I c #E52121", -"J c #E31C1C", -"K c #670C0C", -"L c #380606", -"M c #420808", -"N c #6D0C0C", -"O c #F07777", -"P c #FEEEEE", -"Q c #F9C6C6", -"R c #F49D9D", -"S c #EC5D5D", -"T c #E83C3C", -"U c #E62121", -"V c #E41A1A", -"W c #E41D1D", -"X c #E21E1E", -"Y c #E41C1C", -"Z c #E51C1C", -"[ c #C71717", -"] c #720C0C", -"^ c #330606", -"_ c #640C0C", -"` c #EF7171", -"a c #FCE3E3", -"b c #F6AFAF", -"c c #F28D8D", -"d c #E72E2E", -"e c #E62020", -"f c #E51A1A", -"g c #E51F1F", -"h c #CA1818", -"i c #680C0C", -"j c #260404", -"k c #4F0909", -"l c #540A0A", -"m c #520909", -"n c #E72F2F", -"o c #FAD3D3", -"p c #F4A0A0", -"q c #F17E7E", -"r c #ED5E5E", -"s c #E93E3E", -"t c #E62525", -"u c #E51B1B", -"v c #BD1616", -"w c #941111", -"x c #810E0E", -"y c #830F0F", -"z c #991111", -"{ c #E21A1A", -"| c #B41515", -"} c #420707", -"~ c #8C1010", -" ! c #E62323", -"!! c #C91717", -"#! c #B21515", -"$! c #EB5050", -"%! c #E73030", -"&! c #DC1919", -"'! c #250404", -"(! c #550A0A", -")! c #7B0E0E", -"*! c #BC1616", -"+! c #860F0F", -",! c #310505", -"-! c #3F0707", -".! c #F07676", -"0! c #EB5656", -"1! c #E62727", -"2! c #E62424", -"3! c #E21D1D", -"4! c #DE1919", -"5! c #7A0E0E", -"6! c #470808", -"7! c #350606", -"8! c #5B0A0A", -"9! c #971111", -":! c #DF1919", -";! c #BF1616", -"<! c #951111", -"=! c #EA4E4E", -">! c #E61F1F", -"?! c #E41B1B", -"@! c #E31A1A", -"A! c #D41919", -"B! c #8D1010", -"C! c #5D0B0B", -"D! c #390606", -"E! c #1F0303", -"F! c #4E0909", -"G! c #D61818", -"H! c #750D0D", -"I! c #270404", -"J! c #6A0C0C", -"K! c #E62222", -"L! c #C81717", -"M! c #790D0D", -"N! c #290404", -"O! c #460808", -"P! c #770D0D", -"Q! c #D81818", -"R! c #A21212", -"S! c #E52020", -"T! c #931111", -"U! c #7D0E0E", -"V! c #A61313", -"W! c #450808", -"X! c #3A0606", -"Y! c #570A0A", -"Z! c #2E0505", -"[! c #440808", -"]! c #580A0A", -"^! c #630C0C", -"_! c #BA1616", -"`! c #D51818", -"a! c #180202", -"b! c #EC5959", -"c! c #F39292", -"d! c #3C0707", -"e! c #DF1A1A", -"f! c #6C0C0C", -"g! c #300505", -"h! c #D11818", -"i! c #FFFEFE", -"j! c white", -"k! c #FCDDDD", -"l! c #8A1010", -"m! c #D41818", -"n! c #A91313", -"o! c #730D0D", -"p! c #1D0303", -"q! c #4B0909", -"r! c #AF1414", -"s! c #F39797", -"t! c #FFFBFB", -"u! c #FFFAFA", -"v! c #FDEBEB", -"w! c #FCDEDE", -"x! c #FBD4D4", -"y! c #FBDADA", -"z! c #EB4E4E", -"{! c #880F0F", -"|! c #200303", -"}! c #600B0B", -"~! c #F9CBCB", -" # c #FBD7D7", -"!# c #F8BEBE", -"## c #F5A5A5", -"$# c #F49C9C", -"%# c #F39191", -"&# c #F28989", -"'# c #F07B7B", -"(# c #A71313", -")# c #700D0D", -"*# c #140202", -"+# c #E73333", -",# c #F5A8A8", -"-# c #F39393", -".# c #F18282", -"0# c #F07878", -"1# c #EE6C6C", -"2# c #ED6262", -"3# c #EC5757", -"4# c #E94242", -"5# c #E94141", -"6# c #DA1919", -"7# c #F38E8E", -"8# c #690C0C", -"9# c #760D0D", -":# c #EC5A5A", -";# c #EA4949", -"<# c #E93F3F", -"=# c #E62626", -"># c #DD1919", -"?# c #6F0C0C", -"@# c #2C0505", -"A# c #FEEBEB", -"B# c #F07D7D", -"C# c #6B0C0C", -"D# c #911010", -"E# c #D21818", -"F# c #E31B1B", -"G# c #E11D1D", -"H# c #400707", -"I# c #EE6666", -"J# c #7F0E0E", -"K# c #5C0B0B", -"L# c #E62828", -"M# c #B11414", -"N# c #F39A9A", -"O# c #ED6565", -"P# c #A31313", -"Q# c #370606", -"R# c #840F0F", -"S# c #E21B1B", -"T# c #E31D1D", -"U# c #B61515", -"V# c #ED6161", -"W# c #EB5555", -"X# c #490808", -"Y# c #3B0707", -"Z# c #650C0C", -"[# c #9E1212", -"]# c #E41F1F", -"^# c #E51D1D", -"_# c #800E0E", -"`# c #921111", -"a# c #4A0808", -"b# c #320505", -"c# c #E73535", -"d# c #E72A2A", -"e# c #E72B2B", -"f# c #E42020", -"g# c #B11515", -"h# c #E51E1E", -"i# c #E31E1E", -"j# c #530909", -"k# c #E42121", -"l# c #610B0B", -"m# c #4D0909", -"n# c #DB1A1A", -"o# c #AA1414", -"p# c #620B0B", -"q# c #720D0D", -"r# c #B31515", -"s# c #E11919", -"t# c #C61717", -"u# c #5A0A0A", -"v# c #BB1616", -"w# c #CC1818", -"x# c #C11717", -"y# c #850F0F", -"z# c #1E0303", -"{# c #2B0505", -"|# c #560A0A", -"}# c #5F0B0B", -"~# c #210303", -" $ c #170202", -" ", -" # $ % & # ", -" ' ( ) * + , - . ) 0 $ ", -" 1 2 3 4 5 6 7 8 9 : ; < = 2 # ", -" > ) ? @ A B C D E F G H I J < K L ", -" M N O P Q R 8 S T U V W X Y Z I [ ] & ", -" ^ _ ` a b c D E d e G f Y g e W Y f h i j ", -" k l l m 2 n o p q r s t u v w x y z v { f f f | 2 ", -"} ~ d !!!#!q C ` $!%!g &!~ 0 1 '!j L (!)!*!f f f +!,! ", -"-!*!.!0!4 1!Y 2!d 2!3!4!5!6! 7!8!9!:!f ;!2 ", -"% <!=!: >!?!V @!{ V W A!B!C!D! E!F!x G!f H!E! ", -"I!J!e K!?!f ?!u ?!J f f f L!M!N! O!P!Q!R!1 ", -" l < S!f ?!u ?!J f f f f f T!# } U!V!W! ", -" X!= V Z u ?!J f f f f f + Y! Z![!]!^!]! ", -" 8!_!I ?!J f f f f `!T!0 a! ,!Y!#!b!c!;!l ", -" d!P!e!Z f f f 4!+ f!X! g!]!h!R i!j!j!k!l!& ", -" 2 +!{ f m!n!o!W!p! q!r!s!t!u!v!w!x!y!z!Y! ", -" O!]!x {!_ > |! }!F ~! #!#b ##$#%#&#'#~ X! ", -" & (#)#6!*# 8!+#,#-#.#0#1#2#3#=!4#5#;!(! ", -" '!6#7#8#Z! 9#S :#;#<#: F =#I Z 3!Y >#?#@# ", -" U!A#B#C#X! m D#E#X F#G#V G#F#J Y 3!Y T!H# ", -" ( 2#y!I#J#O! W!K#v L#Y J f f f f f f M#0 ", -" ,!r!$#N#O#P#]!Q# W!R#S#U T#?!T#X ?!V f f U#Y! ", -" 8!? 1#V#W#h!y C!X#Y#q!Z#[#S#]#W G ^#G ?!* _#`#w P!a# ", -" b#J#? c#d#e#f#h g#+ | `!g h#Y Y i#Y f V!j#^ & D!' ", -" 6!l!J h#J W k#U K!U ]#Y ?!f f f f U#l#g! ", -" m#{!n#e h#i#J u f f f f f f f o#p#X! ", -" W!q#r#s#f f f f f f f f t#{!u#b# ", -" Z!2 P!- v#w#G!h!x#o#y#p#O!z# ", -" {#> |#}#p#}!8!m#X!~# ", -" $ $ ", -" "};
\ No newline at end of file diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp index b974fb89..68cebae0 100644 --- a/RealtimeSync/application.cpp +++ b/RealtimeSync/application.cpp @@ -13,6 +13,7 @@ #include "../shared/localization.h" #include "xmlFreeFileSync.h" #include "../shared/standardPaths.h" +#include <wx/file.h> #ifdef FFS_LINUX #include <gtk/gtk.h> @@ -80,3 +81,30 @@ void Application::OnStartApplication(wxIdleEvent& event) frame->SetIcon(*GlobalResources::getInstance().programIcon); //set application icon frame->Show(); } + + +bool Application::OnExceptionInMainLoop() +{ + throw; //just re-throw exception and avoid display of additional exception messagebox: it will be caught in OnRun() +} + + +int Application::OnRun() +{ + try + { + wxApp::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(FreeFileSync::getLastErrorTxtFile(), wxFile::write); + safeOutput.Write(wxString::FromAscii(e.what())); + + wxMessageBox(wxString::FromAscii(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR); + return -9; + } + + return 0; //program's return value +} + diff --git a/RealtimeSync/application.h b/RealtimeSync/application.h index e7116156b..d95cb3b4 100644 --- a/RealtimeSync/application.h +++ b/RealtimeSync/application.h @@ -16,11 +16,13 @@ class Application : public wxApp { public: virtual bool OnInit(); + virtual int OnRun(); + virtual bool OnExceptionInMainLoop(); private: void OnStartApplication(wxIdleEvent& event); - std::auto_ptr<wxHelpController> helpController; //global help controller + std::auto_ptr<wxHelpController> helpController; //global help controller }; #endif // REALTIMESYNCAPP_H diff --git a/RealtimeSync/functions.h b/RealtimeSync/functions.h index 3d7d522f..0001a7ec 100644 --- a/RealtimeSync/functions.h +++ b/RealtimeSync/functions.h @@ -9,7 +9,7 @@ class wxDirPickerCtrl; namespace RealtimeSync { - void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); +void setDirectoryName(const wxString& dirname, wxTextCtrl* txtCtrl, wxDirPickerCtrl* dirPicker); } #endif // FUNCTIONS_H_INCLUDED diff --git a/RealtimeSync/guiGenerated.cpp b/RealtimeSync/guiGenerated.cpp index 7e705927..aa4a8261 100644 --- a/RealtimeSync/guiGenerated.cpp +++ b/RealtimeSync/guiGenerated.cpp @@ -13,7 +13,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) { - this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + this->SetSizeHints( wxSize( 420,440 ), wxDefaultSize ); m_menubar1 = new wxMenuBar( 0 ); m_menuFile = new wxMenu(); @@ -56,9 +56,35 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( 0, 10, 0, 0, 5 ); - m_staticText2 = new wxStaticText( m_panelMain, wxID_ANY, _("Usage: Select directories for monitoring and enter a commandline. Each time files are modified within these directories (or subdirectories) the commandline is executed."), wxDefaultPosition, wxDefaultSize, 0|wxDOUBLE_BORDER ); - m_staticText2->Wrap( 350 ); - bSizer1->Add( m_staticText2, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 40 ); + wxStaticBoxSizer* sbSizer41; + sbSizer41 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, wxEmptyString ), wxVERTICAL ); + + m_staticText2 = new wxStaticText( m_panelMain, wxID_ANY, _("Usage:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + m_staticText2->SetFont( wxFont( 10, 74, 90, 90, true, wxT("Tahoma") ) ); + + sbSizer41->Add( m_staticText2, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_staticText3 = new wxStaticText( m_panelMain, wxID_ANY, _("1. Select directories to monitor."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText3->Wrap( -1 ); + sbSizer41->Add( m_staticText3, 0, wxLEFT, 10 ); + + m_staticText4 = new wxStaticText( m_panelMain, wxID_ANY, _("2. Enter a command line."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText4->Wrap( -1 ); + sbSizer41->Add( m_staticText4, 0, wxLEFT, 10 ); + + m_staticText5 = new wxStaticText( m_panelMain, wxID_ANY, _("3. Press 'Start'."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText5->Wrap( -1 ); + sbSizer41->Add( m_staticText5, 0, wxLEFT, 10 ); + + m_staticline3 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + sbSizer41->Add( m_staticline3, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); + + m_staticText21 = new wxStaticText( m_panelMain, wxID_ANY, _("The command line is executed each time:\n- Files within these directories (or subdirectories) are modified\n- The corresponding drive letter becomes available (USB-insert)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText21->Wrap( -1 ); + sbSizer41->Add( m_staticText21, 0, wxRIGHT|wxLEFT|wxEXPAND, 5 ); + + bSizer1->Add( sbSizer41, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 40 ); m_staticline2 = new wxStaticLine( m_panelMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); bSizer1->Add( m_staticline2, 0, wxTOP|wxBOTTOM|wxEXPAND, 10 ); @@ -119,7 +145,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer1->Add( bSizer8, 1, wxEXPAND, 5 ); wxStaticBoxSizer* sbSizer3; - sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Commandline") ), wxVERTICAL ); + sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Command line") ), wxVERTICAL ); m_textCtrlCommand = new wxTextCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); sbSizer3->Add( m_textCtrlCommand, 0, wxEXPAND|wxBOTTOM, 5 ); @@ -133,7 +159,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_panelMain, wxID_ANY, _("Delay") ), wxVERTICAL ); m_spinCtrlDelay = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 0, 2000000000, 0 ); - m_spinCtrlDelay->SetToolTip( _("Delay between detection of changes and execution of commandline in seconds") ); + m_spinCtrlDelay->SetToolTip( _("Delay between detection of changes and execution of command line in seconds") ); sbSizer4->Add( m_spinCtrlDelay, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 ); diff --git a/RealtimeSync/guiGenerated.h b/RealtimeSync/guiGenerated.h index 91669af8..7be541d4 100644 --- a/RealtimeSync/guiGenerated.h +++ b/RealtimeSync/guiGenerated.h @@ -23,14 +23,14 @@ class wxButtonWithImage; #include <wx/settings.h> #include <wx/stattext.h> #include <wx/statline.h> +#include <wx/sizer.h> +#include <wx/statbox.h> #include <wx/bmpbuttn.h> #include <wx/button.h> -#include <wx/sizer.h> #include <wx/textctrl.h> #include <wx/filepicker.h> #include <wx/panel.h> #include <wx/scrolwin.h> -#include <wx/statbox.h> #include <wx/spinctrl.h> #include <wx/frame.h> @@ -52,6 +52,11 @@ class MainDlgGenerated : public wxFrame wxPanel* m_panelMain; wxStaticText* m_staticText2; + wxStaticText* m_staticText3; + wxStaticText* m_staticText4; + wxStaticText* m_staticText5; + wxStaticLine* m_staticline3; + wxStaticText* m_staticText21; wxStaticLine* m_staticline2; wxPanel* m_panelMainFolder; wxBitmapButton* m_bpButtonAddFolder; diff --git a/RealtimeSync/mainDialog.cpp b/RealtimeSync/mainDialog.cpp index 8d9c7d7a..81af1ce0 100644 --- a/RealtimeSync/mainDialog.cpp +++ b/RealtimeSync/mainDialog.cpp @@ -2,7 +2,6 @@ #include "resources.h" #include "../shared/customButton.h" #include "../shared/standardPaths.h" -//#include "../shared/globalFunctions.h" #include <wx/msgdlg.h> #include <wx/wupdlock.h> #include "watcher.h" @@ -13,6 +12,8 @@ #include "xmlFreeFileSync.h" #include "../shared/systemConstants.h" #include "../shared/stringConv.h" +#include "../shared/staticAssert.h" +#include "../shared/buildInfo.h" using namespace FreeFileSync; @@ -20,17 +21,17 @@ using namespace FreeFileSync; MainDialog::MainDialog(wxDialog *dlg, const wxString& cfgFilename, wxHelpController& helpController) - : MainDlgGenerated(dlg), - helpController_(helpController) + : MainDlgGenerated(dlg), + helpController_(helpController) { wxWindowUpdateLocker dummy(this); //avoid display distortion m_bpButtonRemoveTopFolder->Hide(); m_panelMainFolder->Layout(); - m_bpButtonAddFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapAddFolderPair); - m_bpButtonRemoveTopFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); - m_buttonStart->setBitmapFront(*GlobalResources::getInstance().bitmapStart); + m_bpButtonAddFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("addFolderPair"))); + m_bpButtonRemoveTopFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); + m_buttonStart->setBitmapFront(GlobalResources::getInstance().getImageByName(wxT("startRed"))); m_buttonStart->SetFocus(); //register key event @@ -126,11 +127,11 @@ const wxString& MainDialog::lastConfigFileName() void MainDialog::OnShowHelp(wxCommandEvent& event) { - #ifdef FFS_WIN +#ifdef FFS_WIN helpController_.DisplaySection(wxT("html\\advanced\\RealtimeSync.html")); - #elif defined FFS_LINUX +#elif defined FFS_LINUX helpController_.DisplaySection(wxT("html/advanced/RealtimeSync.html")); - #endif +#endif } @@ -139,11 +140,18 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event) //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode)"); + build += wxT(" - Unicode"); #else - build += wxT(" - ANSI)"); + build += wxT(" - ANSI"); #endif //wxUSE_UNICODE + //compile time info about 32/64-bit build + if (Utility::is64BitBuild) + build += wxT(" x64)"); + else + build += wxT(" x86)"); + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + wxMessageDialog* aboutDlg = new wxMessageDialog(this, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK); aboutDlg->ShowModal(); } @@ -356,7 +364,7 @@ void MainDialog::addFolder(const std::vector<wxString>& newFolders, bool addFron { //add new folder pair FolderPanel* newFolder = new FolderPanel(m_scrolledWinFolders); - newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(*GlobalResources::getInstance().bitmapRemoveFolderPair); + newFolder->m_bpButtonRemoveFolder->SetBitmapLabel(GlobalResources::getInstance().getImageByName(wxT("removeFolderPair"))); //get size of scrolled window folderHeight = newFolder->GetSize().GetHeight(); diff --git a/RealtimeSync/mainDialog.h b/RealtimeSync/mainDialog.h index 8447d269..8a5e87bf 100644 --- a/RealtimeSync/mainDialog.h +++ b/RealtimeSync/mainDialog.h @@ -16,7 +16,7 @@ namespace xmlAccess { - struct XmlRealConfig; +struct XmlRealConfig; } @@ -24,8 +24,8 @@ class FolderPanel : public FolderGenerated { public: FolderPanel(wxWindow* parent) : - FolderGenerated(parent), - dragDropOnFolder(new FreeFileSync::DragDropOnDlg(this, m_dirPicker, m_txtCtrlDirectory)) {} + FolderGenerated(parent), + dragDropOnFolder(new FreeFileSync::DragDropOnDlg(this, m_dirPicker, m_txtCtrlDirectory)) {} private: //support for drag and drop diff --git a/RealtimeSync/resources.cpp b/RealtimeSync/resources.cpp index fe2a5ced..eeb89563 100644 --- a/RealtimeSync/resources.cpp +++ b/RealtimeSync/resources.cpp @@ -19,12 +19,7 @@ const GlobalResources& GlobalResources::getInstance() GlobalResources::GlobalResources() { - //map, allocate and initialize pictures - bitmapResource[wxT("start red.png")] = (bitmapStart = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("add pair.png")] = (bitmapAddFolderPair = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("remove pair.png")] = (bitmapRemoveFolderPair = new wxBitmap(wxNullBitmap)); - - programIcon = new wxIcon(wxNullIcon); + programIcon = new wxIcon(wxNullIcon); } @@ -49,7 +44,6 @@ void GlobalResources::load() const wxZipInputStream resourceFile(input); - std::map<wxString, wxBitmap*>::iterator bmp; while (true) { std::auto_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); @@ -58,24 +52,31 @@ void GlobalResources::load() const const wxString name = entry->GetName(); - //search if entry is available in map - if ((bmp = bitmapResource.find(name)) != bitmapResource.end()) - *(bmp->second) = wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG)); + //generic image loading + if (name.EndsWith(wxT(".png"))) + { + if (bitmapResource.find(name) == bitmapResource.end()) //avoid duplicate entry: prevent memory leak! + bitmapResource[name] = new wxBitmap(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")); #else -#include "RealtimeSync.xpm" - *programIcon = wxIcon(RealtimeSync_xpm); + //use big logo bitmap for better quality + programIcon->CopyFromBitmap(getImageByName(wxT("RealtimeSync.png"))); #endif } const wxBitmap& GlobalResources::getImageByName(const wxString& imageName) const { - std::map<wxString, wxBitmap*>::const_iterator bmp = bitmapResource.find(imageName); + const std::map<wxString, wxBitmap*>::const_iterator bmp = imageName.Find(wxChar('.')) == wxNOT_FOUND ? //assume .png ending if nothing else specified + bitmapResource.find(imageName + wxT(".png")) : + bitmapResource.find(imageName); + if (bmp != bitmapResource.end()) return *bmp->second; else diff --git a/RealtimeSync/resources.h b/RealtimeSync/resources.h index 3a0cde7b..6a6cd976 100644 --- a/RealtimeSync/resources.h +++ b/RealtimeSync/resources.h @@ -14,10 +14,6 @@ public: const wxBitmap& getImageByName(const wxString& imageName) const; //image resource objects - wxBitmap* bitmapStart; - wxBitmap* bitmapAddFolderPair; - wxBitmap* bitmapRemoveFolderPair; - wxIcon* programIcon; void load() const; //loads bitmap resources on program startup: logical const! diff --git a/RealtimeSync/trayMenu.cpp b/RealtimeSync/trayMenu.cpp index 5d9d2430..01bcda48 100644 --- a/RealtimeSync/trayMenu.cpp +++ b/RealtimeSync/trayMenu.cpp @@ -10,6 +10,8 @@ #include <wx/timer.h> #include <wx/utils.h> #include <wx/log.h> +#include "../shared/staticAssert.h" +#include "../shared/buildInfo.h" class RtsTrayIcon; @@ -42,9 +44,9 @@ class RtsTrayIcon : public wxTaskBarIcon { public: RtsTrayIcon(WaitCallbackImpl* callback) : - m_callback(callback) + m_callback(callback) { - wxTaskBarIcon::SetIcon(*GlobalResources::getInstance().programIcon, wxT("RealtimeSync")); + wxTaskBarIcon::SetIcon(*GlobalResources::getInstance().programIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active...")); //register double-click Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIcon::resumeToMain), NULL, this); @@ -89,11 +91,18 @@ private: //build information wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__; #if wxUSE_UNICODE - build += wxT(" - Unicode)"); + build += wxT(" - Unicode"); #else - build += wxT(" - ANSI)"); + build += wxT(" - ANSI"); #endif //wxUSE_UNICODE + //compile time info about 32/64-bit build + if (Utility::is64BitBuild) + build += wxT(" x64)"); + else + build += wxT(" x86)"); + assert_static(Utility::is32BitBuild || Utility::is64BitBuild); + wxMessageDialog* aboutDlg = new wxMessageDialog(NULL, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK); aboutDlg->ShowModal(); aboutDlg->Destroy(); @@ -145,8 +154,8 @@ private: WaitCallbackImpl::WaitCallbackImpl() : - m_abortRequested(false), - m_resumeRequested(false) + m_abortRequested(false), + m_resumeRequested(false) { trayMenu.reset(new RtsTrayIcon(this)); } @@ -172,7 +181,7 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces WaitCallbackImpl callback; if (config.commandline.empty()) - throw FreeFileSync::FileError(_("Commandline is empty!")); + throw FreeFileSync::FileError(_("Command line is empty!")); long lastExec = 0; while (true) diff --git a/RealtimeSync/trayMenu.h b/RealtimeSync/trayMenu.h index 04b07f8a..99f2f90a 100644 --- a/RealtimeSync/trayMenu.h +++ b/RealtimeSync/trayMenu.h @@ -7,13 +7,13 @@ namespace RealtimeSync { - enum MonitorResponse - { - RESUME, - QUIT - }; +enum MonitorResponse +{ + RESUME, + QUIT +}; - MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config); +MonitorResponse startDirectoryMonitor(const xmlAccess::XmlRealConfig& config); } diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 97471397..67dae521 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -5,9 +5,15 @@ #include <wx/filefn.h> #include "../shared/fileHandling.h" #include "../shared/stringConv.h" +#include <stdexcept> +#include <map> +#include <wx/timer.h> #ifdef FFS_WIN +//#include "../shared/fileId.h" +//#include "Dbt.h" #include <wx/msw/wrapwin.h> //includes "windows.h" +#include "../shared/longPathPrefix.h" #elif defined FFS_LINUX #include <wx/timer.h> @@ -20,6 +26,191 @@ using namespace FreeFileSync; #ifdef FFS_WIN +/* +template <class T> //have a disctinct static variable per class! +class InstanceCounter //exception safety!!!! use RAII for counter inc/dec! +{ +public: + InstanceCounter() + { + ++instanceCount; + //we're programming on global variables: only one instance of NotifyDeviceArrival allowed at a time! + if (instanceCount > 1) + throw std::logic_error("Only one instance of NotifyDeviceArrival allowed!"); + } + ~InstanceCounter() + { + --instanceCount; + } +private: + static size_t instanceCount; //this class needs to be a singleton but with variable lifetime! => count instances to check consistency +}; +template <class T> //we need a disctinct static variable per class! +size_t InstanceCounter<T>::instanceCount = 0; + + +std::set<Zstring> driveNamesArrived; //letters of newly arrived drive names + + +//convert bitmask into "real" drive-letter +void notifyDriveFromMask (ULONG unitmask) +{ + for (wchar_t i = 0; i < 26; ++i) + { + if (unitmask & 0x1) + { + Zstring newDrivePath; + newDrivePath += DefaultChar('A') + i; + newDrivePath += DefaultStr(":\\"); + driveNamesArrived.insert(newDrivePath); + return; + } + unitmask = unitmask >> 1; + } +} + + +LRESULT CALLBACK MainWndProc( + HWND hwnd, // handle to window + UINT uMsg, // message identifier + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + + //detect device arrival: http://msdn.microsoft.com/en-us/library/aa363215(VS.85).aspx + if (uMsg == WM_DEVICECHANGE) + { + if (wParam == DBT_DEVICEARRIVAL) + { + PDEV_BROADCAST_HDR lpdb = reinterpret_cast<PDEV_BROADCAST_HDR>(lParam); + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) + { + PDEV_BROADCAST_VOLUME lpdbv = reinterpret_cast<PDEV_BROADCAST_VOLUME>(lpdb); + //warning: lpdbv->dbcv_flags is 0 for USB-sticks! + + //insert drive name notification into global variable: + notifyDriveFromMask(lpdbv->dbcv_unitmask); + } + } + } + //default + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + + +class NotifyDeviceArrival //e.g. insertion of USB-Stick +{ +public: + NotifyDeviceArrival() : + parentInstance(NULL), + registeredClass(NULL), + windowHandle(NULL) + { + //get program's module handle + parentInstance = GetModuleHandle(NULL); + if (parentInstance == NULL) + throw FreeFileSync::FileError(wxString(("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted()+ wxT(" (GetModuleHandle)")); + + //register the main window class + WNDCLASS wc; + wc.style = 0; + wc.lpfnWndProc = MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = parentInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = wxT("DeviceArrivalWatcher"); + + registeredClass =:: RegisterClass(&wc); + if (registeredClass == 0) + throw FreeFileSync::FileError(wxString(("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted()+ wxT(" (RegisterClass)")); + + //create dummy-window + windowHandle = ::CreateWindow( + reinterpret_cast<LPCTSTR>(registeredClass), //LPCTSTR lpClassName OR ATOM in low-order word! + 0, //LPCTSTR lpWindowName, + 0, //DWORD dwStyle, + 0, //int x, + 0, //int y, + 0, //int nWidth, + 0, //int nHeight, + 0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)! + NULL, //HMENU hMenu, + parentInstance, //HINSTANCE hInstance, + NULL); //LPVOID lpParam + if (windowHandle == NULL) + throw FreeFileSync::FileError(wxString( ("Could not start monitoring for volume arrival:")) + wxT("\n\n") + + FreeFileSync::getLastErrorFormatted() + wxT(" (CreateWindow)")); + + //clear global variable + driveNamesArrived.clear(); + } + + ~NotifyDeviceArrival() + { + //clean-up in reverse order + if (windowHandle != NULL) + ::DestroyWindow(windowHandle); + + if (registeredClass != 0) + ::UnregisterClass(reinterpret_cast<LPCTSTR>(registeredClass), //LPCTSTR lpClassName OR ATOM in low-order word! + parentInstance); //HINSTANCE hInstance + } + + + //test if one of the notifications matches one of the directory paths specified + bool notificationsFound(const std::vector<Zstring>& dirList) const + { + //do NOT rely on string parsing! use (volume directory) file ids! + std::set<Utility::FileID> notifiedIds; + for (std::set<Zstring>::const_iterator j = driveNamesArrived.begin(); j != driveNamesArrived.end(); ++j) + { + const Utility::FileID notifiedVolId = Utility::retrieveFileID(*j); + if (notifiedVolId != Utility::FileID()) + notifiedIds.insert(notifiedVolId); + } + //clear global variable + driveNamesArrived.clear(); + + if (!notifiedIds.empty()) //minor optimization + { + for (std::vector<Zstring>::const_iterator i = dirList.begin(); i != dirList.end(); ++i) + { + //retrieve volume name + wchar_t volumeNameRaw[1000]; + if (::GetVolumePathName(i->c_str(), //__in LPCTSTR lpszFileName, + volumeNameRaw, //__out LPTSTR lpszVolumePathName, + 1000)) //__in DWORD cchBufferLength + { + const Utility::FileID monitoredId = Utility::retrieveFileID(volumeNameRaw); + if (monitoredId != Utility::FileID()) + { + if (notifiedIds.find(monitoredId) != notifiedIds.end()) + return true; + } + } + } + } + + return false; + } + +private: + HINSTANCE parentInstance; + ATOM registeredClass; + HWND windowHandle; + + //we're programming on global variables: only one instance of NotifyDeviceArrival allowed at a time! + InstanceCounter<NotifyDeviceArrival> dummy; //exception safety!!!! use RAII for counter inc/dec! +}; +*/ + +//-------------------------------------------------------------------------------------------------------------- class ChangeNotifications { public: @@ -75,11 +266,53 @@ private: #endif +class NotifyDirectoryArrival //detect changes to directory availability +{ +public: + //initialization + void addForMonitoring(const Zstring& dirName, bool isExisting) //dir-existence already checked by calling method, avoid double-checking -> consistency! + { + availablility[dirName] = isExisting; + } + + //detection + bool changeDetected() //polling explicitly allowed! + { + const int UPDATE_INTERVAL = 1000; //1 second interval + + static wxLongLong lastExec = 0; + const wxLongLong newExec = wxGetLocalTimeMillis(); + + if (newExec - lastExec >= UPDATE_INTERVAL) + { + lastExec = newExec; + + for (std::map<Zstring, bool>::iterator i = availablility.begin(); i != availablility.end(); ++i) + if (FreeFileSync::dirExists(i->first) != i->second) //change in availability + { + if (i->second) //directory doesn't exist anymore: no reason to trigger the commandline! (sometimes triggered by ChangeNotifications anyway...) + i->second = false; //update value, so that dir-arrival will be detected next time + else //directory arrival: trigger commandline! + return true; + } + } + + return false; + } + +private: + std::map<Zstring, bool> availablility; //save avail. status for each directory +}; + + void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler) { if (dirNames.empty()) //pathological case, but check is needed later return; + //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks) + NotifyDirectoryArrival monitorAvailability; + #ifdef FFS_WIN ChangeNotifications notifications; @@ -88,47 +321,58 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(i->c_str()); if (formattedDir.empty()) - throw FreeFileSync::FileError(_("Please fill all empty directory fields.")); - else if (!FreeFileSync::dirExists(formattedDir)) - throw FreeFileSync::FileError(wxString(_("Directory does not exist:")) + wxT("\n") + - wxT("\"") + zToWx(formattedDir) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted()); - - const HANDLE rv = ::FindFirstChangeNotification( - formattedDir.c_str(), //__in LPCTSTR lpPathName, - true, //__in BOOL bWatchSubtree, - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE); //__in DWORD dwNotifyFilter - - if (rv == INVALID_HANDLE_VALUE) + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); + + const bool isExisting = FreeFileSync::dirExists(formattedDir); + if (isExisting) { - const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + *i + wxT("\""); - throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + const HANDLE rv = ::FindFirstChangeNotification( + FreeFileSync::applyLongPathPrefix(formattedDir).c_str(), //__in LPCTSTR lpPathName, + true, //__in BOOL bWatchSubtree, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE); //__in DWORD dwNotifyFilter + + if (rv == INVALID_HANDLE_VALUE) + { + const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + *i + wxT("\""); + throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + } + + notifications.addHandle(rv); } + //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick - notifications.addHandle(rv); + monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant } while (true) { - const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context - notifications.getSize(), //__in DWORD nCount, - notifications.getArray(), //__in const HANDLE *lpHandles, - false, //__in BOOL bWaitAll, - UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds - if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) - return; //directory change detected - else if (rv == WAIT_FAILED) - throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); - else if (rv == WAIT_TIMEOUT) - statusHandler->requestUiRefresh(); + //check for changes within directories: + if (notifications.getSize() > 0) + { + const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context + notifications.getSize(), //__in DWORD nCount, + notifications.getArray(), //__in const HANDLE *lpHandles, + false, //__in BOOL bWaitAll, + UI_UPDATE_INTERVAL); //__in DWORD dwMilliseconds + if (WAIT_OBJECT_0 <= rv && rv < WAIT_OBJECT_0 + notifications.getSize()) + return; //directory change detected + else if (rv == WAIT_FAILED) + throw FreeFileSync::FileError(wxString(_("Error when monitoring directories.")) + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + //else if (rv == WAIT_TIMEOUT) + } + + if (monitorAvailability.changeDetected()) //check for newly arrived devices: + return; + + statusHandler->requestUiRefresh(); } #elif defined FFS_LINUX - std::vector<std::string> fullDirList; + std::vector<std::string> fullDirList; //including subdirectories! //add all subdirectories for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i) @@ -136,17 +380,19 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(wxToZ(*i)); if (formattedDir.empty()) - throw FreeFileSync::FileError(_("Please fill all empty directory fields.")); + throw FreeFileSync::FileError(_("At least one directory input field is empty.")); - else if (!FreeFileSync::dirExists(formattedDir)) - throw FreeFileSync::FileError(wxString(_("Directory does not exist:")) + wxT("\n") + - wxT("\"") + zToWx(formattedDir) + wxT("\"") + wxT("\n\n") + - FreeFileSync::getLastErrorFormatted()); + const bool isExisting = FreeFileSync::dirExists(formattedDir); + if (isExisting) + { + fullDirList.push_back(formattedDir.c_str()); + //get all subdirectories + DirsOnlyTraverser traverser(fullDirList); + FreeFileSync::traverseFolder(formattedDir, false, &traverser); //don't traverse into symlinks (analog to windows build) + } + //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick - fullDirList.push_back(formattedDir.c_str()); - //get all subdirectories - DirsOnlyTraverser traverser(fullDirList); - FreeFileSync::traverseFolder(formattedDir, false, &traverser); //don't traverse into symlinks (analog to windows build) + monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant } try @@ -178,6 +424,7 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal } } + while (true) { notifications.WaitForEvents(); //called in non-blocking mode @@ -185,6 +432,9 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal if (notifications.GetEventCount() > 0) return; //directory change detected + if (monitorAvailability.changeDetected()) //check for newly arrived devices: + return; + wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL); statusHandler->requestUiRefresh(); } @@ -199,3 +449,10 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal } #endif } + + + + + + + diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h index 1655eebf..2f3990c2 100644 --- a/RealtimeSync/watcher.h +++ b/RealtimeSync/watcher.h @@ -8,16 +8,16 @@ namespace RealtimeSync { - 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; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss - class WaitCallback - { - public: - virtual ~WaitCallback() {} - virtual void requestUiRefresh() = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() - }; +class WaitCallback +{ +public: + virtual ~WaitCallback() {} + virtual void requestUiRefresh() = 0; //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() +}; - void waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler); //throw(FreeFileSync::FileError); +void waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler); //throw(FreeFileSync::FileError); } #endif // WATCHER_H_INCLUDED diff --git a/RealtimeSync/xmlFreeFileSync.h b/RealtimeSync/xmlFreeFileSync.h index 8de9af08..55687d93 100644 --- a/RealtimeSync/xmlFreeFileSync.h +++ b/RealtimeSync/xmlFreeFileSync.h @@ -8,9 +8,9 @@ namespace RealtimeSync { - void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::XmlError); +void readRealOrBatchConfig(const wxString& filename, xmlAccess::XmlRealConfig& config); //throw (xmlAccess::XmlError); - int getProgramLanguage(); +int getProgramLanguage(); } #endif // XMLFREEFILESYNC_H_INCLUDED diff --git a/RealtimeSync/xmlProcessing.h b/RealtimeSync/xmlProcessing.h index 90842abf..b8207973 100644 --- a/RealtimeSync/xmlProcessing.h +++ b/RealtimeSync/xmlProcessing.h @@ -8,16 +8,16 @@ namespace xmlAccess { - struct XmlRealConfig - { - XmlRealConfig() : delay(5) {} - std::vector<wxString> directories; - wxString commandline; - unsigned int delay; - }; +struct XmlRealConfig +{ + XmlRealConfig() : delay(5) {} + std::vector<wxString> directories; + wxString commandline; + unsigned int delay; +}; - void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError); - void writeRealConfig(const XmlRealConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); +void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError); +void writeRealConfig(const XmlRealConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); } #endif // XMLPROCESSING_H_INCLUDED |