summaryrefslogtreecommitdiff
path: root/ui/batch_status_handler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui/batch_status_handler.cpp')
-rw-r--r--ui/batch_status_handler.cpp288
1 files changed, 163 insertions, 125 deletions
diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp
index ba70de39..9d57b4e3 100644
--- a/ui/batch_status_handler.cpp
+++ b/ui/batch_status_handler.cpp
@@ -15,16 +15,56 @@
#include "../shared/global_func.h"
#include "../shared/app_main.h"
#include "../shared/util.h"
+#include "../shared/file_traverser.h"
using namespace ffs3;
+namespace
+{
+class FindLogfiles : public ffs3::TraverseCallback
+{
+public:
+ FindLogfiles(const Zstring& prefix, std::vector<Zstring>& logfiles) : prefix_(prefix), logfiles_(logfiles) {}
+
+ virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details)
+ {
+ const Zstring fileName(shortName);
+ if (fileName.StartsWith(prefix_) && fileName.EndsWith(Zstr(".log")))
+ logfiles_.push_back(fullName);
+ }
+
+ virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) {}
+
+ virtual ReturnValDir onDir(const Zchar* shortName, const Zstring& fullName)
+ {
+ return Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>(); //DON'T traverse into subdirs
+ }
+
+ virtual void onError(const wxString& errorText) {} //errors are not really critical in this context
+
+private:
+ const Zstring prefix_;
+ std::vector<Zstring>& logfiles_;
+};
+
+void removeFileNoThrow(const Zstring& filename)
+{
+ try
+ {
+ ffs3::removeFile(filename);
+ }
+ catch(...) {}
+}
+}
+
+
class LogFile
{
public:
- LogFile(const wxString& logfileDirectory, const wxString& jobName) //throw (FileError&)
+ LogFile(const wxString& logfileDirectory, const wxString& jobName) : jobName_(jobName) //throw (FileError&)
{
- const wxString logfileName = findUniqueLogname(logfileDirectory, jobName);
+ logfileName = findUniqueLogname(logfileDirectory, jobName);
logFile.Open(logfileName, wxT("w"));
if (!logFile.IsOpened())
@@ -50,8 +90,8 @@ public:
void writeLog(const ErrorLogging& log)
{
//write actual logfile
- const ErrorLogging::MessageEntry& messages = log.getFormattedMessages();
- for (ErrorLogging::MessageEntry::const_iterator i = messages.begin(); i != messages.end(); ++i)
+ const std::vector<wxString>& messages = log.getFormattedMessages();
+ for (std::vector<wxString>::const_iterator i = messages.begin(); i != messages.end(); ++i)
logFile.Write(*i + wxChar('\n'));
}
@@ -65,6 +105,23 @@ public:
logFile.Write(wxString(_("Stop")) + wxT(" (") + _("Total time:") + wxT(" ") + (wxTimeSpan::Milliseconds(time)).Format() + wxT(")"));
}
+ void limitLogfileCount(size_t maxCount) const
+ {
+ std::vector<Zstring> logFiles;
+ FindLogfiles traverseCallback(wxToZ(jobName_), logFiles);
+
+ traverseFolder(wxToZ(logfileName).BeforeLast(common::FILE_NAME_SEPARATOR), //throw();
+ false, //follow Symlinks
+ traverseCallback);
+
+ if (logFiles.size() <= maxCount)
+ return;
+
+ //delete oldest logfiles
+ std::sort(logFiles.begin(), logFiles.end()); //take advantage of logfile naming convention to sort by age
+ std::for_each(logFiles.begin(), logFiles.end() - maxCount, ::removeFileNoThrow);
+ }
+
private:
static wxString findUniqueLogname(const wxString& logfileDirectory, const wxString& jobName)
{
@@ -101,6 +158,8 @@ private:
return output;
}
+ const wxString jobName_;
+ wxString logfileName;
wxFFile logFile;
wxStopWatch totalTime;
};
@@ -110,6 +169,7 @@ private:
BatchStatusHandler::BatchStatusHandler(bool runSilent,
const wxString& jobName,
const wxString* logfileDirectory,
+ size_t logFileMaxCount,
const xmlAccess::OnError handleError,
const SwitchToGui& switchBatchToGui, //functionality to change from batch mode to GUI mode
int& returnVal) :
@@ -121,11 +181,12 @@ BatchStatusHandler::BatchStatusHandler(bool runSilent,
returnValue(returnVal),
syncStatusFrame(*this, NULL, runSilent, jobName)
{
- if (logfileDirectory)
+ if (logfileDirectory && logFileMaxCount > 0)
{
try
{
logFile.reset(new LogFile(*logfileDirectory, jobName));
+ logFile->limitLogfileCount(logFileMaxCount);
}
catch (ffs3::FileError& error)
{
@@ -141,21 +202,21 @@ BatchStatusHandler::BatchStatusHandler(bool runSilent,
BatchStatusHandler::~BatchStatusHandler()
{
- const int totalErrors = errorLog.errorsTotal(); //evaluate before finalizing log
+ const int totalErrors = errorLog.typeCount(TYPE_ERROR | TYPE_FATAL_ERROR); //evaluate before finalizing log
//finalize error log
if (abortIsRequested())
{
returnValue = -4;
- errorLog.logError(_("Synchronization aborted!"));
+ errorLog.logMsg(_("Synchronization aborted!"), TYPE_ERROR);
}
- else if (totalErrors)
+ else if (totalErrors > 0)
{
returnValue = -5;
- errorLog.logWarning(_("Synchronization completed with errors!"));
+ errorLog.logMsg(_("Synchronization completed with errors!"), TYPE_WARNING);
}
else
- errorLog.logInfo(_("Synchronization completed successfully!"));
+ errorLog.logMsg(_("Synchronization completed successfully!"), TYPE_INFO);
//print the results list: logfile
@@ -170,32 +231,16 @@ BatchStatusHandler::~BatchStatusHandler()
}
else if (!exitWhenFinished || syncStatusFrame.getAsWindow()->IsShown()) //warning: wxWindow::Show() is called within processHasFinished()!
{
- //print the results list: GUI
- wxString finalMessage;
- if (totalErrors > 0)
- {
- wxString header(_("Warning: Synchronization failed for %x item(s):"));
- header.Replace(wxT("%x"), ffs3::numberToStringSep(totalErrors), false);
- finalMessage += header + wxT("\n\n");
- }
-
- const ErrorLogging::MessageEntry& messages = errorLog.getFormattedMessages();
- for (ErrorLogging::MessageEntry::const_iterator i = messages.begin(); i != messages.end(); ++i)
- {
- finalMessage += *i;
- finalMessage += wxT("\n\n");
- }
-
//notify about (logical) application main window => program won't quit, but stay on this dialog
ffs3::AppMainWindow::setMainWindow(syncStatusFrame.getAsWindow());
//notify to syncStatusFrame that current process has ended
if (abortIsRequested())
- syncStatusFrame.processHasFinished(SyncStatus::ABORTED, finalMessage); //enable okay and close events
- else if (totalErrors)
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_ERROR, finalMessage);
+ syncStatusFrame.processHasFinished(SyncStatus::ABORTED, errorLog); //enable okay and close events
+ else if (totalErrors > 0)
+ syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_ERROR, errorLog);
else
- syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS, finalMessage);
+ syncStatusFrame.processHasFinished(SyncStatus::FINISHED_WITH_SUCCESS, errorLog);
}
else
syncStatusFrame.closeWindowDirectly(); //syncStatusFrame is main window => program will quit directly
@@ -205,8 +250,8 @@ BatchStatusHandler::~BatchStatusHandler()
inline
void BatchStatusHandler::reportInfo(const Zstring& text)
{
- if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING && logFile.get()) //write file transfer information to log
- errorLog.logInfo(zToWx(text)); //avoid spamming with file copy info: visually identifying warning messages has priority! however when saving to a log file wee need this info
+ if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) //write file transfer information to log
+ errorLog.logMsg(zToWx(text), TYPE_INFO); //avoid spamming with file copy info: visually identifying warning messages has priority! however when saving to a log file wee need this info
syncStatusFrame.setStatusText_NoUpdate(text);
}
@@ -218,21 +263,21 @@ void BatchStatusHandler::initNewProcess(int objectsTotal, wxLongLong dataTotal,
switch (currentProcess)
{
- case StatusHandler::PROCESS_SCANNING:
- syncStatusFrame.resetGauge(0, 0); //initialize some gui elements (remaining time, speed)
- syncStatusFrame.setCurrentStatus(SyncStatus::SCANNING);
- break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- syncStatusFrame.resetGauge(objectsTotal, dataTotal);
- syncStatusFrame.setCurrentStatus(SyncStatus::COMPARING_CONTENT);
- break;
- case StatusHandler::PROCESS_SYNCHRONIZING:
- syncStatusFrame.resetGauge(objectsTotal, dataTotal);
- syncStatusFrame.setCurrentStatus(SyncStatus::SYNCHRONIZING);
- break;
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
+ case StatusHandler::PROCESS_SCANNING:
+ syncStatusFrame.resetGauge(0, 0); //initialize some gui elements (remaining time, speed)
+ syncStatusFrame.setCurrentStatus(SyncStatus::SCANNING);
+ break;
+ case StatusHandler::PROCESS_COMPARING_CONTENT:
+ syncStatusFrame.resetGauge(objectsTotal, dataTotal);
+ syncStatusFrame.setCurrentStatus(SyncStatus::COMPARING_CONTENT);
+ break;
+ case StatusHandler::PROCESS_SYNCHRONIZING:
+ syncStatusFrame.resetGauge(objectsTotal, dataTotal);
+ syncStatusFrame.setCurrentStatus(SyncStatus::SYNCHRONIZING);
+ break;
+ case StatusHandler::PROCESS_NONE:
+ assert(false);
+ break;
}
}
@@ -242,70 +287,64 @@ void BatchStatusHandler::updateProcessedData(int objectsProcessed, wxLongLong da
{
switch (currentProcess)
{
- case StatusHandler::PROCESS_SCANNING:
- syncStatusFrame.incScannedObjects_NoUpdate(objectsProcessed);
- break;
- case StatusHandler::PROCESS_COMPARING_CONTENT:
- case StatusHandler::PROCESS_SYNCHRONIZING:
- syncStatusFrame.incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed);
- break;
- case StatusHandler::PROCESS_NONE:
- assert(false);
- break;
+ case StatusHandler::PROCESS_SCANNING:
+ syncStatusFrame.incScannedObjects_NoUpdate(objectsProcessed);
+ break;
+ case StatusHandler::PROCESS_COMPARING_CONTENT:
+ case StatusHandler::PROCESS_SYNCHRONIZING:
+ syncStatusFrame.incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed);
+ break;
+ case StatusHandler::PROCESS_NONE:
+ assert(false);
+ break;
}
}
-void BatchStatusHandler::logInfo(const wxString& infoMessage)
-{
- errorLog.logInfo(infoMessage);
-}
-
-
void BatchStatusHandler::reportWarning(const wxString& warningMessage, bool& warningActive)
{
- errorLog.logWarning(warningMessage);
+ errorLog.logMsg(warningMessage, TYPE_WARNING);
if (!warningActive)
return;
switch (handleError_)
{
- case xmlAccess::ON_ERROR_POPUP:
- {
- //show popup and ask user how to handle warning
- bool dontWarnAgain = false;
- WarningDlg warningDlg(NULL,
- WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_SWITCH | WarningDlg::BUTTON_ABORT,
- warningMessage + wxT("\n\n") + _("Press \"Switch\" to open FreeFileSync GUI mode."),
- dontWarnAgain);
- warningDlg.Raise();
- const WarningDlg::Response rv = static_cast<WarningDlg::Response>(warningDlg.ShowModal());
- switch (rv)
+ case xmlAccess::ON_ERROR_POPUP:
{
- case WarningDlg::BUTTON_ABORT:
- abortThisProcess();
- break;
+ //show popup and ask user how to handle warning
+ bool dontWarnAgain = false;
+ WarningDlg warningDlg(NULL,
+ WarningDlg::BUTTON_IGNORE | WarningDlg::BUTTON_SWITCH | WarningDlg::BUTTON_ABORT,
+ warningMessage + wxT("\n\n") + _("Press \"Switch\" to open FreeFileSync GUI mode."),
+ dontWarnAgain);
+ warningDlg.Raise();
+ const WarningDlg::Response rv = static_cast<WarningDlg::Response>(warningDlg.ShowModal());
+ switch (rv)
+ {
+ case WarningDlg::BUTTON_ABORT:
+ abortThisProcess();
+ break;
+
+ case WarningDlg::BUTTON_SWITCH:
+ errorLog.logMsg(_("Switching to FreeFileSync GUI mode..."), TYPE_WARNING);
+ switchToGuiRequested = true;
+ abortThisProcess();
+ break;
+
+ case WarningDlg::BUTTON_IGNORE: //no unhandled error situation!
+ warningActive = !dontWarnAgain;
+ break;
+ }
+ }
+ break; //keep it! last switch might not find match
- case WarningDlg::BUTTON_SWITCH:
- errorLog.logWarning(_("Switching to FreeFileSync GUI mode..."));
- switchToGuiRequested = true;
+ case xmlAccess::ON_ERROR_EXIT: //abort
abortThisProcess();
break;
- case WarningDlg::BUTTON_IGNORE: //no unhandled error situation!
- warningActive = !dontWarnAgain;
+ case xmlAccess::ON_ERROR_IGNORE: //no unhandled error situation!
break;
- }
- }
- break; //keep it! last switch might not find match
-
- case xmlAccess::ON_ERROR_EXIT: //abort
- abortThisProcess();
- break;
-
- case xmlAccess::ON_ERROR_IGNORE: //no unhandled error situation!
- break;
}
}
@@ -314,40 +353,40 @@ ErrorHandler::Response BatchStatusHandler::reportError(const wxString& errorMess
{
switch (handleError_)
{
- case xmlAccess::ON_ERROR_POPUP:
- {
- bool ignoreNextErrors = false;
- ErrorDlg errorDlg(NULL,
- ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT,
- errorMessage,
- ignoreNextErrors);
- errorDlg.Raise();
- const ErrorDlg::ReturnCodes rv = static_cast<ErrorDlg::ReturnCodes>(errorDlg.ShowModal());
- switch (rv)
+ case xmlAccess::ON_ERROR_POPUP:
{
- case ErrorDlg::BUTTON_IGNORE:
- if (ignoreNextErrors) //falsify only
- handleError_ = xmlAccess::ON_ERROR_IGNORE;
- errorLog.logError(errorMessage);
- return ErrorHandler::IGNORE_ERROR;
-
- case ErrorDlg::BUTTON_RETRY:
- return ErrorHandler::RETRY;
-
- case ErrorDlg::BUTTON_ABORT:
- errorLog.logError(errorMessage);
- abortThisProcess();
+ bool ignoreNextErrors = false;
+ ErrorDlg errorDlg(NULL,
+ ErrorDlg::BUTTON_IGNORE | ErrorDlg::BUTTON_RETRY | ErrorDlg::BUTTON_ABORT,
+ errorMessage,
+ ignoreNextErrors);
+ errorDlg.Raise();
+ const ErrorDlg::ReturnCodes rv = static_cast<ErrorDlg::ReturnCodes>(errorDlg.ShowModal());
+ switch (rv)
+ {
+ case ErrorDlg::BUTTON_IGNORE:
+ if (ignoreNextErrors) //falsify only
+ handleError_ = xmlAccess::ON_ERROR_IGNORE;
+ errorLog.logMsg(errorMessage, TYPE_ERROR);
+ return ErrorHandler::IGNORE_ERROR;
+
+ case ErrorDlg::BUTTON_RETRY:
+ return ErrorHandler::RETRY;
+
+ case ErrorDlg::BUTTON_ABORT:
+ errorLog.logMsg(errorMessage, TYPE_ERROR);
+ abortThisProcess();
+ }
}
- }
- break; //used if last switch didn't find a match
+ break; //used if last switch didn't find a match
- case xmlAccess::ON_ERROR_EXIT: //abort
- errorLog.logError(errorMessage);
- abortThisProcess();
+ case xmlAccess::ON_ERROR_EXIT: //abort
+ errorLog.logMsg(errorMessage, TYPE_ERROR);
+ abortThisProcess();
- case xmlAccess::ON_ERROR_IGNORE:
- errorLog.logError(errorMessage);
- return ErrorHandler::IGNORE_ERROR;
+ case xmlAccess::ON_ERROR_IGNORE:
+ errorLog.logMsg(errorMessage, TYPE_ERROR);
+ return ErrorHandler::IGNORE_ERROR;
}
assert(false);
@@ -361,8 +400,7 @@ void BatchStatusHandler::reportFatalError(const wxString& errorMessage)
if (handleError_ == xmlAccess::ON_ERROR_POPUP)
exitWhenFinished = false; //log fatal error and show it on status dialog
- errorLog.logFatalError(errorMessage);
- abortThisProcess();
+ errorLog.logMsg(errorMessage, TYPE_FATAL_ERROR);
}
bgstack15