summaryrefslogtreecommitdiff
path: root/RealtimeSync
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:15 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:15 +0200
commit8318453bf9d4fd50b137ff6c6fc8d1fd22aa6395 (patch)
tree975c6e590c31e56007006a23e7b15d0245d75b08 /RealtimeSync
parent3.6 (diff)
downloadFreeFileSync-8318453bf9d4fd50b137ff6c6fc8d1fd22aa6395.tar.gz
FreeFileSync-8318453bf9d4fd50b137ff6c6fc8d1fd22aa6395.tar.bz2
FreeFileSync-8318453bf9d4fd50b137ff6c6fc8d1fd22aa6395.zip
3.7
Diffstat (limited to 'RealtimeSync')
-rw-r--r--RealtimeSync/RealtimeSync.cbp62
-rw-r--r--RealtimeSync/RealtimeSync.vcproj4
-rw-r--r--RealtimeSync/mainDialog.cpp3
-rw-r--r--RealtimeSync/makefile8
-rw-r--r--RealtimeSync/trayMenu.cpp79
-rw-r--r--RealtimeSync/watcher.cpp208
-rw-r--r--RealtimeSync/watcher.h14
-rw-r--r--RealtimeSync/xmlProcessing.h2
8 files changed, 234 insertions, 146 deletions
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp
index 9a5d9f93..24b6d859 100644
--- a/RealtimeSync/RealtimeSync.cbp
+++ b/RealtimeSync/RealtimeSync.cbp
@@ -7,32 +7,6 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
- <Target title="Debug">
- <Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" />
- <Option working_dir="..\BUILD" />
- <Option object_output="..\OBJ\Debug_RTS_GCC" />
- <Option type="0" />
- <Option compiler="gcc" />
- <Option projectLinkerOptionsRelation="2" />
- <Compiler>
- <Add option="-g" />
- <Add option="-Winvalid-pch" />
- <Add option='-include &quot;pch.h&quot;' />
- <Add option="-D__WXDEBUG__" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" />
- </Compiler>
- <ResourceCompiler>
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswud" />
- </ResourceCompiler>
- <Linker>
- <Add library="libwxmsw28ud_core.a" />
- <Add library="libwxmsw28ud_adv.a" />
- <Add library="libwxbase28ud.a" />
- <Add library="libwxpngd.a" />
- <Add library="libwxzlibd.a" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" />
- </Linker>
- </Target>
<Target title="Release">
<Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" />
<Option working_dir="..\BUILD" />
@@ -45,9 +19,6 @@
<Add option="-DNDEBUG" />
<Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
</Compiler>
- <ResourceCompiler>
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
- </ResourceCompiler>
<Linker>
<Add option="-s" />
<Add library="libwxmsw28u_core.a" />
@@ -58,12 +29,38 @@
<Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" />
</Linker>
</Target>
+ <Target title="Debug-DLL">
+ <Option output="..\BUILD\RealtimeSync" prefix_auto="1" extension_auto="1" />
+ <Option working_dir="..\BUILD" />
+ <Option object_output="..\OBJ\Debug_RTS_GCC" />
+ <Option type="0" />
+ <Option compiler="gcc" />
+ <Option projectLinkerOptionsRelation="2" />
+ <Compiler>
+ <Add option="-g" />
+ <Add option="-Winvalid-pch" />
+ <Add option='-include &quot;pch.h&quot;' />
+ <Add option="-D__WXDEBUG__" />
+ <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll\mswud" />
+ </Compiler>
+ <Linker>
+ <Add library="libwxmsw28ud_core.a" />
+ <Add library="libwxmsw28ud_adv.a" />
+ <Add library="libwxbase28ud.a" />
+ <Add library="libwxpngd.a" />
+ <Add library="libwxzlibd.a" />
+ <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll" />
+ </Linker>
+ </Target>
</Build>
<Compiler>
+ <Add option="-Wshadow" />
+ <Add option="-Winit-self" />
+ <Add option="-Wswitch-enum" />
+ <Add option="-Wmain" />
<Add option="-Wall" />
<Add option="-pipe" />
<Add option="-mthreads" />
- <Add option='[[if (PLATFORM == PLATFORM_MSW &amp;&amp; (GetCompilerFactory().GetCompilerVersionString(_T(&quot;gcc&quot;)) &gt;= _T(&quot;4.0.0&quot;))) print(_T(&quot;-Wno-attributes&quot;));]]' />
<Add option="-D__GNUWIN32__" />
<Add option="-D__WXMSW__" />
<Add option="-DwxUSE_UNICODE" />
@@ -71,7 +68,6 @@
<Add option="-DZSTRING_WIDE_CHAR" />
<Add option="-DTIXML_USE_STL" />
<Add directory="C:\Programme\C++\wxWidgets\include" />
- <Add directory="C:\Programme\C++\wxWidgets\contrib\include" />
<Add directory="..\shared\boost_1_x" />
</Compiler>
<ResourceCompiler>
@@ -79,6 +75,7 @@
</ResourceCompiler>
<Linker>
<Add option="-mthreads" />
+ <Add option="-Wl,--enable-auto-import" />
<Add library="libkernel32.a" />
<Add library="libuser32.a" />
<Add library="libuuid.a" />
@@ -101,7 +98,7 @@
<Unit filename="pch.h">
<Option compile="1" />
<Option weight="0" />
- <Option target="Debug" />
+ <Option target="Debug-DLL" />
</Unit>
<Unit filename="resource.rc">
<Option compilerVar="WINDRES" />
@@ -138,7 +135,6 @@
<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 8d60d6ba..8e95f3a6 100644
--- a/RealtimeSync/RealtimeSync.vcproj
+++ b/RealtimeSync/RealtimeSync.vcproj
@@ -432,10 +432,6 @@
>
</File>
<File
- RelativePath="..\shared\recycler.cpp"
- >
- </File>
- <File
RelativePath=".\resources.cpp"
>
</File>
diff --git a/RealtimeSync/mainDialog.cpp b/RealtimeSync/mainDialog.cpp
index 72b19a35..5ba378ce 100644
--- a/RealtimeSync/mainDialog.cpp
+++ b/RealtimeSync/mainDialog.cpp
@@ -8,6 +8,7 @@
#include "resources.h"
#include "../shared/customButton.h"
#include "../shared/standardPaths.h"
+#include "functions.h"
#include <wx/msgdlg.h>
#include <wx/wupdlock.h>
#include "watcher.h"
@@ -288,7 +289,7 @@ void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg)
m_textCtrlCommand->SetValue(cfg.commandline);
//set delay
- m_spinCtrlDelay->SetValue(cfg.delay);
+ m_spinCtrlDelay->SetValue(static_cast<int>(cfg.delay));
}
diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile
index 8f42e2e3..9692e22a 100644
--- a/RealtimeSync/makefile
+++ b/RealtimeSync/makefile
@@ -18,6 +18,7 @@ FILE_LIST+=xmlProcessing.cpp
FILE_LIST+=xmlFreeFileSync.cpp
FILE_LIST+=../library/processXml.cpp
FILE_LIST+=../structures.cpp
+FILE_LIST+=../shared/localization_no_BOM.cpp
FILE_LIST+=../shared/inotify/inotify-cxx.cpp
FILE_LIST+=../shared/tinyxml/tinyxml.cpp
FILE_LIST+=../shared/tinyxml/tinystr.cpp
@@ -31,7 +32,6 @@ FILE_LIST+=../shared/xmlBase.cpp
FILE_LIST+=../shared/customButton.cpp
FILE_LIST+=../shared/fileHandling.cpp
FILE_LIST+=../shared/fileTraverser.cpp
-FILE_LIST+=../shared/localization.cpp
FILE_LIST+=../shared/standardPaths.cpp
FILE_LIST+=../shared/helpProvider.cpp
FILE_LIST+=../shared/fileIO.cpp
@@ -50,8 +50,8 @@ init:
#remove byte ordering mark: needed by Visual C++ but an error with GCC
removeBOM: ../tools/removeBOM.cpp
- g++ -o removeBOM ../tools/removeBOM.cpp
- ./removeBOM ../shared/localization.cpp
+ g++ -o OBJ/removeBOM ../tools/removeBOM.cpp
+ ./OBJ/removeBOM ../shared/localization.cpp ../shared/localization_no_BOM.cpp
%.dep : %.cpp
#strip path information
@@ -63,7 +63,7 @@ RealtimeSync: init removeBOM $(DEP_LIST)
clean:
rm -rf OBJ
rm -f ../BUILD/$(APPNAME)
- rm -f removeBOM
+ rm -f ../shared/localization_no_BOM.cpp
install:
if [ ! -d $(BINDIR) ] ; then mkdir -p $(BINDIR); fi
diff --git a/RealtimeSync/trayMenu.cpp b/RealtimeSync/trayMenu.cpp
index 79076abd..436ee904 100644
--- a/RealtimeSync/trayMenu.cpp
+++ b/RealtimeSync/trayMenu.cpp
@@ -9,7 +9,9 @@
#include <wx/taskbar.h>
#include <wx/app.h>
#include "resources.h"
-//#include <memory>
+#include <algorithm>
+#include <iterator>
+#include "../shared/stringConv.h"
#include <wx/utils.h>
#include <wx/menu.h>
#include "watcher.h"
@@ -23,7 +25,7 @@
using namespace RealtimeSync;
-class WaitCallbackImpl : private wxEvtHandler, public RealtimeSync::WaitCallback //keep this order: else VC++ generated wrong code
+class WaitCallbackImpl : private wxEvtHandler, public RealtimeSync::WaitCallback //keep this order: else VC++ generates wrong code
{
public:
WaitCallbackImpl();
@@ -31,6 +33,9 @@ public:
virtual void requestUiRefresh();
+ void showIconActive();
+ void showIconWaiting();
+
void requestAbort()
{
m_abortRequested = true;
@@ -114,13 +119,7 @@ WaitCallbackImpl::WaitCallbackImpl() :
{
trayMenu = new RtsTrayIcon(this); //not in initialization list: give it a valid parent object!
-#ifdef FFS_WIN
- const wxIcon& realtimeIcon = *GlobalResources::getInstance().programIcon;
-#elif defined FFS_LINUX
- wxIcon realtimeIcon;
- realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit
-#endif
- trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active..."));
+ showIconActive();
//register double-click
trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this);
@@ -139,6 +138,30 @@ WaitCallbackImpl::~WaitCallbackImpl()
}
+void WaitCallbackImpl::showIconActive()
+{
+ wxIcon realtimeIcon;
+#ifdef FFS_WIN
+ realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_win.png"))); //use a 16x16 bitmap
+#elif defined FFS_LINUX
+ realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit
+#endif
+ trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active..."));
+}
+
+
+void WaitCallbackImpl::showIconWaiting()
+{
+ wxIcon realtimeIcon;
+#ifdef FFS_WIN
+ realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_waiting_win.png"))); //use a 16x16 bitmap
+#elif defined FFS_LINUX
+ realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_waiting_linux.png"))); //use a 22x22 bitmap for perfect fit
+#endif
+ trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Waiting for all directories to become available..."));
+}
+
+
void WaitCallbackImpl::OnContextMenuSelection(wxCommandEvent& event)
{
const int eventId = event.GetId();
@@ -188,9 +211,22 @@ void WaitCallbackImpl::requestUiRefresh()
}
//##############################################################################################################
+namespace
+{
+std::vector<Zstring> convert(const std::vector<wxString>& dirList)
+{
+ std::vector<Zstring> output;
+ std::transform(dirList.begin(), dirList.end(),
+ std::back_inserter(output), static_cast<Zstring (*)(const wxString&)>(FreeFileSync::wxToZ));
+ return output;
+}
+}
+
RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config)
{
+ const std::vector<Zstring> dirList = convert(config.directories);
+
try
{
WaitCallbackImpl callback;
@@ -198,18 +234,31 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces
if (config.commandline.empty())
throw FreeFileSync::FileError(_("Command line is empty!"));
- long lastExec = 0;
while (true)
{
+ //execute commandline
+ callback.showIconWaiting();
+ waitForMissingDirs(dirList, &callback);
+ callback.showIconActive();
+
wxExecute(config.commandline, wxEXEC_SYNC); //execute command
wxLog::FlushActive(); //show wxWidgets error messages (if any)
- //wait
- waitForChanges(config.directories, &callback);
- lastExec = wxGetLocalTime();
+ //wait for changes (and for all directories to become available)
+ switch (waitForChanges(dirList, &callback))
+ {
+ case CHANGE_DIR_MISSING: //don't execute the commandline before all directories are available!
+ callback.showIconWaiting();
+ waitForMissingDirs(dirList, &callback);
+ callback.showIconActive();
+ break;
+ case CHANGE_DETECTED:
+ break;
+ }
//some delay
- while (wxGetLocalTime() - lastExec < static_cast<long>(config.delay))
+ const long nextExec = wxGetLocalTime() + static_cast<long>(config.delay);
+ while (wxGetLocalTime() < nextExec)
{
callback.requestUiRefresh();
wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL);
@@ -222,7 +271,7 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces
}
catch (const FreeFileSync::FileError& error)
{
- wxMessageBox(error.show().c_str(), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(error.show(), _("Error"), wxOK | wxICON_ERROR);
return RESUME;
}
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp
index 3aa40520..ad9e6508 100644
--- a/RealtimeSync/watcher.cpp
+++ b/RealtimeSync/watcher.cpp
@@ -6,24 +6,22 @@
//
#include "watcher.h"
#include "../shared/systemFunctions.h"
-#include "functions.h"
+//#include "functions.h"
#include <wx/intl.h>
-#include <wx/filefn.h>
-#include "../shared/fileHandling.h"
+//#include <wx/filefn.h>
#include "../shared/stringConv.h"
+#include "../shared/fileHandling.h"
#include <stdexcept>
-#include <map>
+#include <set>
#include <wx/timer.h>
+#include <algorithm>
#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>
-#include <exception>
+//#include <exception>
#include "../shared/inotify/inotify-cxx.h"
#include "../shared/fileTraverser.h"
#endif
@@ -33,8 +31,8 @@ using namespace FreeFileSync;
bool RealtimeSync::updateUiIsAllowed()
{
- static wxLongLong lastExec = 0;
- const wxLongLong newExec = wxGetLocalTimeMillis();
+ static wxLongLong lastExec;
+ const wxLongLong newExec = wxGetLocalTimeMillis();
if (newExec - lastExec >= RealtimeSync::UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary
{
@@ -241,7 +239,7 @@ public:
::FindCloseChangeNotification(*i);
}
- void addHandle(const HANDLE hndl)
+ void addHandle(HANDLE hndl)
{
arrayHandle.push_back(hndl);
}
@@ -266,14 +264,18 @@ class DirsOnlyTraverser : public FreeFileSync::TraverseCallback
public:
DirsOnlyTraverser(std::vector<std::string>& dirs) : m_dirs(dirs) {}
- virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details)
+ virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, bool isSymlink, const FileInfo& details)
{
return TRAVERSING_CONTINUE;
}
- virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName)
+ virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName, bool isSymlink)
{
m_dirs.push_back(fullName.c_str());
- return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), this);
+
+ if (isSymlink) //don't traverse into symlinks (analog to windows build)
+ return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>());
+ else
+ return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), this);
}
virtual ReturnValue onError(const wxString& errorText)
{
@@ -286,107 +288,104 @@ private:
#endif
-class NotifyDirectoryArrival //detect changes to directory availability
+class WatchDirectories //detect changes to directory availability
{
public:
+ WatchDirectories() : allExistingBuffer(true) {}
+
//initialization
- void addForMonitoring(const Zstring& dirName, bool isExisting) //dir-existence already checked by calling method, avoid double-checking -> consistency!
+ void addForMonitoring(const Zstring& dirName)
{
- availablility[dirName] = isExisting;
+ dirList.insert(dirName);
}
- //detection
- bool changeDetected() //polling explicitly allowed!
+ bool allExisting() const //polling explicitly allowed!
{
const int UPDATE_INTERVAL = 1000; //1 second interval
- static wxLongLong lastExec = 0;
- const wxLongLong newExec = wxGetLocalTimeMillis();
-
+ 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;
- }
+ allExistingBuffer = std::find_if(dirList.begin(), dirList.end(), notExisting) == dirList.end();
}
- return false;
+ return allExistingBuffer;
}
private:
- std::map<Zstring, bool> availablility; //save avail. status for each directory, avoid double-entries
+ static bool notExisting(const Zstring& dirname)
+ {
+ return !FreeFileSync::dirExists(dirname);
+ }
+
+ mutable wxLongLong lastExec;
+ mutable bool allExistingBuffer;
+
+ std::set<Zstring> dirList; //save avail. directories, avoid double-entries
};
-void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCallback* statusHandler)
+RealtimeSync::WaitResult RealtimeSync::waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError)
{
- if (dirNames.empty()) //pathological case, but check is needed later
- return;
+ if (dirNames.empty()) //pathological case, but check is needed nevertheless
+ throw FreeFileSync::FileError(_("At least one directory input field is empty."));
- //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks)
- NotifyDirectoryArrival monitorAvailability;
+ //detect when volumes are removed/are not available anymore
+ WatchDirectories dirWatcher;
#ifdef FFS_WIN
ChangeNotifications notifications;
- for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i)
+ for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i)
{
- const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(i->c_str());
+ const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i);
if (formattedDir.empty())
throw FreeFileSync::FileError(_("At least one directory input field is empty."));
- const bool isExisting = FreeFileSync::dirExists(formattedDir);
- if (isExisting)
+ dirWatcher.addForMonitoring(formattedDir);
+
+ 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 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());
- }
+ if (::GetLastError() == ERROR_FILE_NOT_FOUND) //no need to check this condition any earlier!
+ return CHANGE_DIR_MISSING;
- notifications.addHandle(rv);
+ const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(*i) + wxT("\"");
+ throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
}
- //else: we silently ignore this error: it may be that the directory becomes available later, e.g. if it is a USB-stick
- monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant
+ notifications.addHandle(rv);
}
+ if (notifications.getSize() == 0)
+ throw FreeFileSync::FileError(_("At least one directory input field is empty."));
+
while (true)
{
//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
- static_cast<DWORD>(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;
+ const DWORD rv = ::WaitForMultipleObjects( //NOTE: notifications.getArray() returns valid pointer, because it cannot be empty in this context
+ static_cast<DWORD>(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 CHANGE_DETECTED; //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 (!dirWatcher.allExisting()) //check for removed devices:
+ return CHANGE_DIR_MISSING;
statusHandler->requestUiRefresh();
}
@@ -395,24 +394,30 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal
std::vector<std::string> fullDirList; //including subdirectories!
//add all subdirectories
- for (std::vector<wxString>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i)
+ for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i)
{
- const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(wxToZ(*i));
+ const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i);
if (formattedDir.empty())
throw FreeFileSync::FileError(_("At least one directory input field is empty."));
- const bool isExisting = FreeFileSync::dirExists(formattedDir);
- if (isExisting)
+ dirWatcher.addForMonitoring(formattedDir);
+
+
+ fullDirList.push_back(formattedDir.c_str());
+
+ try //get all subdirectories
{
- 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)
+ FreeFileSync::traverseFolder(formattedDir, &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
+ catch (const FreeFileSync::FileError&)
+ {
+ if (!FreeFileSync::dirExists(formattedDir)) //that's no good locking behavior, but better than nothing
+ return CHANGE_DIR_MISSING;
- monitorAvailability.addForMonitoring(formattedDir, isExisting); //all directories (including not yet existing) are relevant
+ throw;
+ }
}
try
@@ -439,21 +444,27 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal
}
catch (const InotifyException& e)
{
+ if (!FreeFileSync::dirExists(i->c_str())) //that's no good locking behavior, but better than nothing
+ return CHANGE_DIR_MISSING;
+
const wxString errorMessage = wxString(_("Could not initialize directory monitoring:")) + wxT("\n\"") + zToWx(i->c_str()) + wxT("\"");
throw FreeFileSync::FileError(errorMessage + wxT("\n\n") + zToWx(e.GetMessage().c_str()));
}
}
+ if (notifications.GetWatchCount() == 0)
+ throw FreeFileSync::FileError(_("At least one directory input field is empty."));
+
while (true)
{
notifications.WaitForEvents(); //called in non-blocking mode
if (notifications.GetEventCount() > 0)
- return; //directory change detected
+ return CHANGE_DETECTED; //directory change detected
- if (monitorAvailability.changeDetected()) //check for newly arrived devices:
- return;
+ if (!dirWatcher.allExisting()) //check for removed devices:
+ return CHANGE_DIR_MISSING;
wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL);
statusHandler->requestUiRefresh();
@@ -470,3 +481,28 @@ void RealtimeSync::waitForChanges(const std::vector<wxString>& dirNames, WaitCal
#endif
}
+
+void RealtimeSync::waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler) //throw(FileError)
+{
+ //new: support for monitoring newly connected directories volumes (e.g.: USB-sticks)
+ WatchDirectories dirWatcher;
+
+ for (std::vector<Zstring>::const_iterator i = dirNames.begin(); i != dirNames.end(); ++i)
+ {
+ const Zstring formattedDir = FreeFileSync::getFormattedDirectoryName(*i);
+
+ if (formattedDir.empty())
+ throw FreeFileSync::FileError(_("At least one directory input field is empty."));
+
+ dirWatcher.addForMonitoring(formattedDir);
+ }
+
+ while (true)
+ {
+ if (dirWatcher.allExisting()) //check for newly arrived devices:
+ return;
+
+ wxMilliSleep(RealtimeSync::UI_UPDATE_INTERVAL);
+ statusHandler->requestUiRefresh();
+ }
+}
diff --git a/RealtimeSync/watcher.h b/RealtimeSync/watcher.h
index 58b20d99..c0690c33 100644
--- a/RealtimeSync/watcher.h
+++ b/RealtimeSync/watcher.h
@@ -7,7 +7,7 @@
#ifndef WATCHER_H_INCLUDED
#define WATCHER_H_INCLUDED
-#include "functions.h"
+#include "../shared/zstring.h"
#include <vector>
#include "../shared/fileError.h"
@@ -26,7 +26,17 @@ public:
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);
+
+//wait until changes are detected or if a directory is not available (anymore)
+enum WaitResult
+{
+ CHANGE_DETECTED,
+ CHANGE_DIR_MISSING
+ };
+WaitResult waitForChanges(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler); //throw(FileError)
+
+//wait until all directories become available (again)
+void waitForMissingDirs(const std::vector<Zstring>& dirNames, WaitCallback* statusHandler); //throw(FileError)
}
#endif // WATCHER_H_INCLUDED
diff --git a/RealtimeSync/xmlProcessing.h b/RealtimeSync/xmlProcessing.h
index f50849b1..bcfcf8f2 100644
--- a/RealtimeSync/xmlProcessing.h
+++ b/RealtimeSync/xmlProcessing.h
@@ -19,7 +19,7 @@ struct XmlRealConfig
XmlRealConfig() : delay(5) {}
std::vector<wxString> directories;
wxString commandline;
- unsigned int delay;
+ size_t delay;
};
void readRealConfig(const wxString& filename, XmlRealConfig& config); //throw (xmlAccess::XmlError);
bgstack15