From 7721cdf1737fb5a99ce60f59acf230b3432576af Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 16:53:46 +0200 Subject: 1.11 --- Application.cpp | 516 +++++++++++++++++++++----------------------------------- 1 file changed, 192 insertions(+), 324 deletions(-) (limited to 'Application.cpp') diff --git a/Application.cpp b/Application.cpp index 371e7107..32bbc132 100644 --- a/Application.cpp +++ b/Application.cpp @@ -11,15 +11,20 @@ #include "ui/mainDialog.h" #include #include +#include #include "library/globalFunctions.h" #include +#include "library/processXml.h" +#include + +using namespace xmlAccess; + IMPLEMENT_APP(Application); bool Application::ProcessIdle() { static bool firstExecution = true; - if (firstExecution) { firstExecution = false; @@ -45,40 +50,38 @@ void Application::initialize() if (!wxSetWorkingDirectory(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath())) throw RuntimeException(_("Could not set working directory to directory containing executable file!")); + globalResource.load(); //load image resources from file: must be called after working directory has been set + //set program language SetExitOnFrameDelete(false); //prevent messagebox from becoming top-level window programLanguage.loadLanguageFromCfg(); SetExitOnFrameDelete(true); - //activate support for .png files - wxImage::AddHandler(new wxPNGHandler); - - //load icon and animation resources (also needed for commandline: status dialog, error dialog - GlobalResources::loadResourceFiles(); - //test if ffs is to be started on UI with config file passed as commandline parameter wxString configFileForUI = FreeFileSync::FfsLastConfigFile; if (argc > 1) { - if (FreeFileSync::isFfsConfigFile(argv[1])) + XmlType xmlConfigType = xmlAccess::getXmlType(argv[1]); + if (xmlConfigType == XML_GUI_CONFIG) configFileForUI = argv[1]; - else //start in commandline mode? + else if (xmlConfigType == XML_BATCH_CONFIG) //start in commandline mode { - parseCommandline(); + runBatchMode(argv[1]); - if (applicationRunsOnCommandLineWithoutWindows) - { + if (applicationRunsInBatchWithoutWindows) ExitMainLoop(); //exit programm on next main loop iteration - return; - } - else - return; //wait for the user to close the status window + return; //program will exit automatically if a main window is present and closed + } + else + { + wxMessageBox(wxString(_("No valid configuration file specified: ")) + argv[1], _("Error"), wxOK | wxICON_ERROR); + return; } } - //start om GUI mode + //start in GUI mode MainDialog* frame = new MainDialog(NULL, configFileForUI, &programLanguage); - frame->SetIcon(*GlobalResources::programIcon); //set application icon + frame->SetIcon(*globalResource.programIcon); //set application icon frame->Show(); } @@ -100,364 +103,229 @@ int Application::OnRun() int Application::OnExit() { - GlobalResources::unloadResourceFiles(); return 0; } -SyncDirection convertCmdlineCfg(const wxString& cfg, const int i) -{ - assert (cfg.Len() == 5); - assert (0 <= i <= 4); - - switch (cfg[i]) - { - case 'L': - return SYNC_DIR_LEFT; - case 'R': - return SYNC_DIR_RIGHT; - case 'N': - return SYNC_DIR_NONE; - default: - assert(false); - return SYNC_DIR_NONE; - } -} - - -void Application::logInit() -{ - wxString tmp = wxDateTime::Now().FormatISOTime(); - tmp.Replace(wxT(":"), wxEmptyString); - wxString logfileName = wxString(wxT("FFS_")) + wxDateTime::Now().FormatISODate() + wxChar('_') + tmp + wxT(".log"); - - logFile.Open(logfileName.c_str(), wxT("w")); - if (!logFile.IsOpened()) - throw RuntimeException(_("Unable to create logfile!")); - logFile.Write(wxString(_("FreeFileSync (Date: ")) + wxDateTime::Now().FormatDate() + _(" Time: ") + wxDateTime::Now().FormatTime() + wxT(")") + wxChar('\n')); - logFile.Write(wxString(_("-------------------------------------------------")) + wxChar('\n')); - logFile.Write(wxChar('\n')); - logFile.Write(_("Log-messages:\n-------------")); - logFile.Write(wxChar('\n')); - logWrite(_("Start")); - logFile.Write(wxChar('\n')); - - totalTime.Start(); //measure total time -} - - -void Application::logWrite(const wxString& logText, const wxString& problemType) +class LogFile { - logFile.Write(wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ")); - - if (problemType != wxEmptyString) - logFile.Write(problemType + wxT(": ")); - - logFile.Write(logText + wxChar('\n')); -} - - -void Application::logClose(const wxString& finalText) -{ - logFile.Write(wxChar('\n')); - - long time = totalTime.Time(); //retrieve total time - logWrite(finalText + wxT(" (") + _("Total time: ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")"), _("Stop")); - - //logFile.close(); <- not needed -} - - -void Application::parseCommandline() -{ - //commandline-descriptor must be initialized here AFTER the program language is set - const wxCmdLineEntryDesc cmdLineDesc [] = +public: + LogFile() { - { wxCMD_LINE_SWITCH, - wxT("h"), - wxT("help"), - _("Displays help on the command line parameters\n"), - wxCMD_LINE_VAL_NONE, - wxCMD_LINE_OPTION_HELP - }, + wxString tmp = wxDateTime::Now().FormatISOTime(); + tmp.Replace(wxT(":"), wxEmptyString); + wxString logfileName = wxString(wxT("FFS_")) + wxDateTime::Now().FormatISODate() + wxChar('_') + tmp + wxT(".log"); + logFile.Open(logfileName.c_str(), wxT("w")); + readyToWrite = logFile.IsOpened(); + if (readyToWrite) { - wxCMD_LINE_OPTION, - GlobalResources::paramCompare, - NULL, - wxString(_("Specify algorithm to test if files are equal:\n\n\t\t")) + GlobalResources::valueSizeDate + _(": check filesize and date\n\t\t") + GlobalResources::valueContent + _(": check file content\n"), - wxCMD_LINE_VAL_STRING, - wxCMD_LINE_OPTION_MANDATORY - }, - - { - wxCMD_LINE_OPTION, - GlobalResources::paramSync, - NULL, - wxString(_("Specify the sync-direction used for each type of file by a string of five chars:\n\n")) + - _("\t\tChar 1: Folders/files that exist on left side only\n") + - _("\t\tChar 2: Folders/files that exist on right side only\n") + - _("\t\tChar 3: Files that exist on both sides, left one is newer\n") + - _("\t\tChar 4: Files that exist on both sides, right one is newer\n") + - _("\t\tChar 5: Files that exist on both sides and are different\n") + - _("\n\t\tSync-direction: L: left, R: right, N: none\n"), - wxCMD_LINE_VAL_STRING, - wxCMD_LINE_OPTION_MANDATORY - }, + logFile.Write(wxString(_("FreeFileSync (Date: ")) + wxDateTime::Now().FormatDate() + _(" Time: ") + wxDateTime::Now().FormatTime() + wxT(")") + wxChar('\n')); + logFile.Write(wxString(_("-------------------------------------------------")) + wxChar('\n')); + logFile.Write(wxChar('\n')); + logFile.Write(_("Log-messages:\n-------------")); + logFile.Write(wxChar('\n')); + write(_("Start")); + logFile.Write(wxChar('\n')); + + totalTime.Start(); //measure total time + } + } - { - wxCMD_LINE_PARAM, - NULL, - NULL, - _(""), - wxCMD_LINE_VAL_STRING - }, + ~LogFile() {} - { - wxCMD_LINE_PARAM, - NULL, - NULL, - _(""), - wxCMD_LINE_VAL_STRING - }, + bool isOkay() + { + return readyToWrite; + } + void write(const wxString& logText, const wxString& problemType = wxEmptyString) + { + if (readyToWrite) { - wxCMD_LINE_OPTION, - GlobalResources::paramInclude, - NULL, - _("Specify names to be included separated by ';'. Wildcards '*' and '?' are supported. Default: \"*\"\n"), - wxCMD_LINE_VAL_STRING, - }, + logFile.Write(wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ")); - { - wxCMD_LINE_OPTION, - GlobalResources::paramExclude, - NULL, - _("Specify names to be excluded separated by ';'. Wildcards '*' and '?' are supported. Default: \"\"\n"), - wxCMD_LINE_VAL_STRING, - }, + if (problemType != wxEmptyString) + logFile.Write(problemType + wxT(": ")); - { - wxCMD_LINE_SWITCH, - GlobalResources::paramContinueError, - NULL, - _("If errors occur during folder comparison or synchronization they are ignored and the process continues.\n") - }, + logFile.Write(logText + wxChar('\n')); + } + } + void close(const wxString& finalText) + { + if (readyToWrite) { - wxCMD_LINE_SWITCH, - GlobalResources::paramRecycler, - NULL, - _("Move files to Recycle Bin instead of deleting or overwriting them directly.\n") - }, + logFile.Write(wxChar('\n')); - { - wxCMD_LINE_SWITCH, - GlobalResources::paramSilent, - NULL, - wxString(_("Do not show graphical status and error messages but write to a logfile instead.\n\n")) + - _("\tExamples:\n\n\t1.) FreeFileSync -comp SIZEDATE -sync RRRRR C:\\Source C:\\Target\n\t2.) FreeFileSync -comp sizedate -sync rlrln c:\\dir1 c:\\dir2 -incl *.doc\n\n") + - _("\t1: Creates a mirror backup of the left directory\n\t2: Synchronizes all *.doc files from both directories simultaneously\n\n") + - _("\tHint: You can easily generate a batch file by chosing \"Create batch job\" from the GUI menubar.\n") - }, + long time = totalTime.Time(); //retrieve total time + write(finalText + wxT(" (") + _("Total time: ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")"), _("Stop")); - { - wxCMD_LINE_NONE + //logFile.close(); <- not needed } - }; - - //now set the parser with all MANDATORY options and parameters - wxCmdLineParser parser(cmdLineDesc, argc, argv); - parser.SetSwitchChars(wxT("-")); - if (parser.Parse() != 0) //if commandline is used incorrectly: display help dialog and exit program - return; - - //commandline parameters - wxString cmp; - wxString syncCfg; - wxString leftDir; - wxString rightDir; - wxString included; - wxString excluded; - bool continueOnError = parser.Found(GlobalResources::paramContinueError); - bool useRecycler = parser.Found(GlobalResources::paramRecycler); - bool silent = parser.Found(GlobalResources::paramSilent); + } - applicationRunsOnCommandLineWithoutWindows = silent; //this value is needed for the application to decide whether to wait for windows to close or not +private: + bool readyToWrite; + wxFFile logFile; + wxStopWatch totalTime; +}; -//check existence of all commandline parameters - if ( !parser.Found(GlobalResources::paramCompare, &cmp) || - !parser.Found(GlobalResources::paramSync, &syncCfg) || - parser.GetParamCount() != 2) +class DeleteOnExit +{ +public: + DeleteOnExit(LogFile* log) : m_log(log) {} + ~DeleteOnExit() { - parser.Usage(); - return; + if (m_log) delete m_log; } - cmp.UpperCase(); - syncCfg.UpperCase(); - leftDir = parser.GetParam(0); - rightDir = parser.GetParam(1); +private: + LogFile* m_log; +}; -//evaluate filter settings - bool filteringEnabled = false; - if (parser.Found(GlobalResources::paramInclude, &included)) - filteringEnabled = true; - else - included = wxT("*"); - if (parser.Found(GlobalResources::paramExclude, &excluded)) - filteringEnabled = true; - else - excluded = wxEmptyString; - -//until here all options and parameters have been set -//-------------------------------------------------------------------- - -//check consistency of all commandline parameters - if ((cmp != GlobalResources::valueSizeDate && cmp != GlobalResources::valueContent) || - syncCfg.Len() != 5 || - (syncCfg[0] != 'L' && syncCfg[0] != 'R' && syncCfg[0] != 'N') || - (syncCfg[1] != 'L' && syncCfg[1] != 'R' && syncCfg[1] != 'N') || - (syncCfg[2] != 'L' && syncCfg[2] != 'R' && syncCfg[2] != 'N') || - (syncCfg[3] != 'L' && syncCfg[3] != 'R' && syncCfg[3] != 'N') || - (syncCfg[4] != 'L' && syncCfg[4] != 'R' && syncCfg[4] != 'N')) - { - parser.Usage(); +void Application::runBatchMode(const wxString& filename) +{ + applicationRunsInBatchWithoutWindows = false; //default value + + //load XML settings + XmlInput inputFile(filename, XML_BATCH_CONFIG); + + if (!inputFile.loadedSuccessfully()) + { //handle error: file load + wxMessageBox(wxString(_("Could not open configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR); return; } -//init logfile - if (silent) logInit(); + XmlMainConfig mainCfg; //structure to receive main settings + XmlBatchConfig batchCfg; //structure to receive batch settings + if ( inputFile.readXmlMainConfig(mainCfg) && //read main configuration settings + inputFile.readXmlBatchConfig(batchCfg)) //read GUI layout configuration + { + //all settings have been read successfully... - wxString logText; + applicationRunsInBatchWithoutWindows = batchCfg.silent; //this value is needed for the application to decide whether to wait for windows to close or not - //check if directories exist - if (!wxDirExists(FreeFileSync::getFormattedDirectoryName(leftDir))) - { - wxString errorMessage = wxString(_("Directory ")) + wxT("\"") + leftDir + wxT("\"") + _(" does not exist."); - wxString statusMessage = wxString(_("Synchronization aborted!")); - if (silent) + //format directory names + for (vector::iterator i = mainCfg.directoryPairs.begin(); i != mainCfg.directoryPairs.end(); ++i) { - logWrite(errorMessage, _("Warning")); - logClose(statusMessage); + i->leftDirectory = FreeFileSync::getFormattedDirectoryName(i->leftDirectory); + i->rightDirectory = FreeFileSync::getFormattedDirectoryName(i->rightDirectory); } - else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Warning"), wxICON_WARNING); - returnValue = -2; - return; - } - else if (!wxDirExists(FreeFileSync::getFormattedDirectoryName(rightDir))) - { - wxString errorMessage = wxString(_("Directory ")) + wxT("\"") + rightDir + wxT("\"") + _(" does not exist."); - wxString statusMessage = wxString(_("Synchronization aborted!")); - if (silent) - { - logWrite(errorMessage, _("Warning")); - logClose(statusMessage); + //init logfile + LogFile* log = NULL; + if (batchCfg.silent) + log = new LogFile; + DeleteOnExit dummy(log); //delete log object on exit (if not NULL) + + if (log && !log->isOkay()) + { //handle error: file load + wxMessageBox(_("Unable to create logfile!"), _("Error"), wxOK | wxICON_ERROR); + return; } - else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Warning"), wxICON_WARNING); - returnValue = -2; - return; - } - //test existence of Recycle Bin - if (useRecycler) - { - if (!FreeFileSync::recycleBinExists()) + //check if directories exist + wxString errorMessage; + if (!FreeFileSync::foldersAreValidForComparison(mainCfg.directoryPairs, errorMessage)) { - wxString errorMessage = wxString(_("Unable to initialize Recycle Bin!")); - wxString statusMessage = wxString(_("Synchronization aborted!")); - if (silent) + if (batchCfg.silent) { - logWrite(errorMessage, _("Error")); - logClose(statusMessage); + log->write(errorMessage, _("Warning")); + log->close(_("Synchronization aborted!")); } - else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Error"), wxICON_WARNING); + else wxMessageBox(errorMessage + wxT("\n\n") + _("Synchronization aborted!"), _("Warning"), wxICON_WARNING); returnValue = -2; return; } - } - -//until here all options and parameters are consistent -//-------------------------------------------------------------------- - CompareVariant cmpVar = CMP_BY_CONTENT; //dummy value to suppress compiler warning - SyncConfiguration syncConfiguration; - FileCompareResult currentGridData; - if (cmp == GlobalResources::valueSizeDate) - cmpVar = CMP_BY_TIME_SIZE; - else if (cmp == GlobalResources::valueContent) - cmpVar = CMP_BY_CONTENT; - else - assert (false); - - syncConfiguration.exLeftSideOnly = convertCmdlineCfg(syncCfg, 0); - syncConfiguration.exRightSideOnly = convertCmdlineCfg(syncCfg, 1); - syncConfiguration.leftNewer = convertCmdlineCfg(syncCfg, 2); - syncConfiguration.rightNewer = convertCmdlineCfg(syncCfg, 3); - syncConfiguration.different = convertCmdlineCfg(syncCfg, 4); + //test existence of Recycle Bin + if (mainCfg.cfg.useRecycleBin) + { + if (!FreeFileSync::recycleBinExists()) + { + wxString errorMessage = wxString(_("Unable to initialize Recycle Bin!")); + wxString statusMessage = wxString(_("Synchronization aborted!")); + if (batchCfg.silent) + { + log->write(errorMessage, _("Error")); + log->close(statusMessage); + } + else wxMessageBox(errorMessage + wxT("\n\n") + statusMessage, _("Error"), wxICON_WARNING); + + returnValue = -2; + return; + } + } - //begin of synchronization process (all in one try-catch block) - try - { - //class handling status updates and error messages - CommandLineStatusUpdater statusUpdater(this, continueOnError, silent); + //begin of synchronization process (all in one try-catch block) + try + { + FileCompareResult currentGridData; + //class handling status updates and error messages + BatchStatusUpdater statusUpdater(mainCfg.cfg.continueOnError, batchCfg.silent, log); //COMPARE DIRECTORIES - //unsigned int startTime = GetTickCount(); - FreeFileSync::startCompareProcess(currentGridData, - FreeFileSync::getFormattedDirectoryName(leftDir), - FreeFileSync::getFormattedDirectoryName(rightDir), - cmpVar, - &statusUpdater); - //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime)); + //unsigned int startTime = GetTickCount(); + FreeFileSync::startCompareProcess(currentGridData, + mainCfg.directoryPairs, + mainCfg.cfg.compareVar, + &statusUpdater); + //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime)); //APPLY FILTERS - if (filteringEnabled) - FreeFileSync::filterCurrentGridData(currentGridData, included, excluded); + if (mainCfg.cfg.filterIsActive) + FreeFileSync::filterCurrentGridData(currentGridData, mainCfg.cfg.includeFilter, mainCfg.cfg.excludeFilter); //check if there are files/folders to be sync'ed at all - int objectsToCreate = 0; - int objectsToOverwrite = 0; - int objectsToDelete = 0; - double dataToProcess = 0; - FreeFileSync::calcTotalBytesToSync(objectsToCreate, - objectsToOverwrite, - objectsToDelete, - dataToProcess, - currentGridData, - syncConfiguration); - if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0) - { - statusUpdater.noSynchronizationNeeded(); //inform about this special case + int objectsToCreate = 0; + int objectsToOverwrite = 0; + int objectsToDelete = 0; + double dataToProcess = 0; + FreeFileSync::calcTotalBytesToSync(objectsToCreate, + objectsToOverwrite, + objectsToDelete, + dataToProcess, + currentGridData, + mainCfg.cfg.syncConfiguration); + if (objectsToCreate + objectsToOverwrite + objectsToDelete == 0) + { + statusUpdater.noSynchronizationNeeded(); //inform about this special case + + returnValue = -3; + return; + } - returnValue = -3; +//START SYNCHRONIZATION + //unsigned int startTime = GetTickCount(); + FreeFileSync::startSynchronizationProcess(currentGridData, mainCfg.cfg.syncConfiguration, &statusUpdater, mainCfg.cfg.useRecycleBin); + //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime)); + } + catch (AbortThisProcess& theException) //exit used by statusUpdater + { + returnValue = -4; return; } -//START SYNCHRONIZATION - //unsigned int startTime = GetTickCount(); - FreeFileSync::startSynchronizationProcess(currentGridData, syncConfiguration, &statusUpdater, useRecycler); //default: do not use recycle bin since it's not sure if its possible - //wxMessageBox(wxString::Format(wxT("%i"), unsigned(GetTickCount()) - startTime)); } - catch (AbortThisProcess& theException) //exit used by statusUpdater - { - returnValue = -4; + else + { //handle error: parsing + wxMessageBox(wxString(_("Error parsing configuration file ")) + wxT("\"") + filename + wxT("\""), _("Error"), wxOK | wxICON_ERROR); return; } - return; //exit program and skip UI dialogs + return; //exit program } //###################################################################################################### -CommandLineStatusUpdater::CommandLineStatusUpdater(Application* application, bool continueOnError, bool silent) : - app(application), +BatchStatusUpdater::BatchStatusUpdater(bool continueOnError, bool silent, LogFile* log) : + m_log(log), continueErrors(continueOnError), silentMode(silent), currentProcess(-1), @@ -471,7 +339,7 @@ CommandLineStatusUpdater::CommandLineStatusUpdater(Application* application, boo } -CommandLineStatusUpdater::~CommandLineStatusUpdater() +BatchStatusUpdater::~BatchStatusUpdater() { unsigned int failedItems = unhandledErrors.GetCount(); @@ -479,14 +347,14 @@ CommandLineStatusUpdater::~CommandLineStatusUpdater() if (silentMode) { if (abortionRequested) - app->logClose(_("Synchronization aborted!")); + m_log->close(_("Synchronization aborted!")); else if (failedItems) - app->logClose(_("Synchronization completed with errors!")); + m_log->close(_("Synchronization completed with errors!")); else { if (!synchronizationNeeded) - app->logWrite(_("Nothing to synchronize. Both directories adhere to the sync-configuration!"), _("Info")); - app->logClose(_("Synchronization completed successfully.")); + m_log->write(_("Nothing to synchronize. Both directories adhere to the sync-configuration!"), _("Info")); + m_log->close(_("Synchronization completed successfully.")); } } else @@ -528,19 +396,19 @@ CommandLineStatusUpdater::~CommandLineStatusUpdater() inline -void CommandLineStatusUpdater::updateStatusText(const wxString& text) +void BatchStatusUpdater::updateStatusText(const wxString& text) { if (silentMode) { if (currentProcess == FreeFileSync::synchronizeFilesProcess) - app->logWrite(text, _("Info")); + m_log->write(text, _("Info")); } else syncStatusFrame->setStatusText_NoUpdate(text); } -void CommandLineStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID) +void BatchStatusUpdater::initNewProcess(int objectsTotal, double dataTotal, int processID) { currentProcess = processID; @@ -566,7 +434,7 @@ void CommandLineStatusUpdater::initNewProcess(int objectsTotal, double dataTotal inline -void CommandLineStatusUpdater::updateProcessedData(int objectsProcessed, double dataProcessed) +void BatchStatusUpdater::updateProcessedData(int objectsProcessed, double dataProcessed) { if (!silentMode) { @@ -581,12 +449,12 @@ void CommandLineStatusUpdater::updateProcessedData(int objectsProcessed, double } -int CommandLineStatusUpdater::reportError(const wxString& text) +int BatchStatusUpdater::reportError(const wxString& text) { if (silentMode) //write error message log and abort the complete session if necessary { unhandledErrors.Add(text); - app->logWrite(text, _("Error")); + m_log->write(text, _("Error")); if (continueErrors) // <- /|\ before return, the logfile is written!!! return StatusUpdater::continueNext; @@ -633,20 +501,20 @@ int CommandLineStatusUpdater::reportError(const wxString& text) inline -void CommandLineStatusUpdater::forceUiRefresh() +void BatchStatusUpdater::forceUiRefresh() { if (!silentMode) syncStatusFrame->updateStatusDialogNow(); } -void CommandLineStatusUpdater::abortThisProcess() +void BatchStatusUpdater::abortThisProcess() { throw AbortThisProcess(); //abort can be triggered by syncStatusFrame } -void CommandLineStatusUpdater::noSynchronizationNeeded() +void BatchStatusUpdater::noSynchronizationNeeded() { synchronizationNeeded = false;; } -- cgit