Index: src/ch/CfgProperties.h =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/CfgProperties.h (.../CfgProperties.h) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/CfgProperties.h (.../CfgProperties.h) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -21,6 +21,8 @@ #pragma once +#include "TTaskConfiguration.h" + class TConfig; // properties definitions @@ -115,6 +117,11 @@ eFreq_Max }; +/////////////////////////////////////////////////////////////////////////////////////////////// +// specific branches in configuration + +#define BRANCH_TASK_SETTINGS _T("CHConfig.TaskSettings") + ///////////////////////////////////////////////////////////////////////////////////////////// // Properties definitions @@ -126,6 +133,7 @@ typedef val_type value_type;\ static value_type GetDefaultValue() { return def_value; }\ static const wchar_t* GetPropertyName() { return val_name; }\ + static const wchar_t* GetPropertyNamePrefix() { return _T(""); }\ } #define PROPERTY_MINMAX(enum_id, val_type, val_name, def_value, min_val, max_val)\ @@ -134,14 +142,25 @@ typedef val_type value_type;\ static value_type GetDefaultValue() { return def_value; }\ static const wchar_t* GetPropertyName() { return val_name; }\ + static const wchar_t* GetPropertyNamePrefix() { return _T(""); }\ } +#define ADAPT_TASK_PROPERTY(enum_id, task_enum_id)\ + template<> struct PropData\ +{\ + typedef TaskPropData::value_type value_type;\ + static value_type GetDefaultValue() { return TaskPropData::GetDefaultValue(); }\ + static const wchar_t* GetPropertyName() { return TaskPropData::GetPropertyName(); }\ + static const wchar_t* GetPropertyNamePrefix() { return BRANCH_TASK_SETTINGS _T("."); }\ +} + const long long Hour = 3600UL*1000UL; const long long Minute = 60UL*1000UL; const long long Second = 1000UL; typedef std::vector CStringVector; +/////////////////////////////////////////////////////////////////////////////////////////////// // General settings PROPERTY(PP_PCLIPBOARDMONITORING, bool, _T("CHConfig.General.Program.EnableClipboardMonitoring"), false); PROPERTY_MINMAX(PP_PMONITORSCANINTERVAL, unsigned int, _T("CHConfig.General.Program.ClipboardMonitorScanInterval"), 1000, 0, 3600UL*1000UL); @@ -191,22 +210,23 @@ PROPERTY(PP_CMLIMITMAXOPERATIONS, unsigned int, _T("CHConfig.Core.Operation.LimitMaxOperations"), 1); -PROPERTY(PP_CMSETDESTATTRIBUTES, bool, _T("CHConfig.Core.Operation.SetDestinationAttributes"), true); -PROPERTY(PP_CMSETDESTDATE, bool, _T("CHConfig.Core.Operation.SetDestinationTime"), true); -PROPERTY(PP_CMPROTECTROFILES, bool, _T("CHConfig.Core.Operation.ProtectReadOnlyFiles"), true); -PROPERTY(PP_CMREADSIZEBEFOREBLOCKING, bool, _T("CHConfig.Core.Operation.ScanForFilesBeforeBlocking"), true); -PROPERTY(PP_CMDEFAULTPRIORITY, int, _T("CHConfig.Core.Operation.Thread.Priority"), THREAD_PRIORITY_NORMAL); -PROPERTY(PP_CMDISABLEPRIORITYBOOST, bool, _T("CHConfig.Core.Operation.Thread.DisablePriorityBoost"), false); -PROPERTY(PP_CMDELETEAFTERFINISHED, bool, _T("CHConfig.Core.Operation.DeleteDilesInSeparateOperation"), true); +// Task default settings (see TTaskConfiguration.h) +ADAPT_TASK_PROPERTY(PP_BFUSEONLYDEFAULT, eTO_UseOnlyDefaultBuffer); +ADAPT_TASK_PROPERTY(PP_BFDEFAULT, eTO_DefaultBufferSize); +ADAPT_TASK_PROPERTY(PP_BFONEDISK, eTO_OneDiskBufferSize); +ADAPT_TASK_PROPERTY(PP_BFTWODISKS, eTO_TwoDisksBufferSize); +ADAPT_TASK_PROPERTY(PP_BFCD, eTO_CDBufferSize); +ADAPT_TASK_PROPERTY(PP_BFLAN, eTO_LANBufferSize); +ADAPT_TASK_PROPERTY(PP_BFUSENOBUFFERING, eTO_DisableBuffering); +ADAPT_TASK_PROPERTY(PP_BFBOUNDARYLIMIT, eTO_DisableBufferingMinSize); -PROPERTY(PP_BFUSEONLYDEFAULT, bool, _T("CHConfig.Core.Operation.Buffer.UseOnlyDefaultBuffer"), false); -PROPERTY_MINMAX(PP_BFDEFAULT, unsigned int, _T("CHConfig.Core.Operation.Buffer.DefaultBufferSize"), 2097152, 1, 0xffffffff); -PROPERTY_MINMAX(PP_BFONEDISK, unsigned int, _T("CHConfig.Core.Operation.Buffer.OnePhysicalDiskSize"), 4194304, 1, 0xffffffff); -PROPERTY_MINMAX(PP_BFTWODISKS, unsigned int, _T("CHConfig.Core.Operation.Buffer.TwoPhysicalDisksSize"), 524288, 1, 0xffffffff); -PROPERTY_MINMAX(PP_BFCD, unsigned int, _T("CHConfig.Core.Operation.Buffer.CDSize"), 262144, 1, 0xffffffff); -PROPERTY_MINMAX(PP_BFLAN, unsigned int, _T("CHConfig.Core.Operation.Buffer.LANSize"), 131072, 1, 0xffffffff); -PROPERTY(PP_BFUSENOBUFFERING, bool, _T("CHConfig.Core.Operation.Buffering.DisableBufferingForLargeFiles"), true); -PROPERTY_MINMAX(PP_BFBOUNDARYLIMIT, int, _T("CHConfig.Core.Operation.Buffering.MinSizeOfFileToDisableBuffering"), 2097152, 1, 0xffffffff); +ADAPT_TASK_PROPERTY(PP_CMSETDESTATTRIBUTES, eTO_SetDestinationAttributes); +ADAPT_TASK_PROPERTY(PP_CMSETDESTDATE, eTO_SetDestinationDateTime); +ADAPT_TASK_PROPERTY(PP_CMPROTECTROFILES, eTO_ProtectReadOnlyFiles); +ADAPT_TASK_PROPERTY(PP_CMREADSIZEBEFOREBLOCKING, eTO_ScanDirectoriesBeforeBlocking); +ADAPT_TASK_PROPERTY(PP_CMDEFAULTPRIORITY, eTO_ThreadPriority); +ADAPT_TASK_PROPERTY(PP_CMDISABLEPRIORITYBOOST, eTO_DisablePriorityBoost); +ADAPT_TASK_PROPERTY(PP_CMDELETEAFTERFINISHED, eTO_DeleteInSeparateSubTask); // Shell extension PROPERTY(PP_SHSHOWCOPY, bool, _T("CHConfig.ShellExtension.ShowCommands.Copy"), true); @@ -220,8 +240,8 @@ PROPERTY(PP_SHSHOWFREESPACE, bool, _T("CHConfig.ShellExtension.ShowFreeSpaceAlongShortcuts"), true); PROPERTY(PP_SHSHOWSHELLICONS, bool, _T("CHConfig.ShellExtension.ShowShortcutsShellIcons"), false); PROPERTY(PP_SHINTERCEPTDRAGDROP, bool, _T("CHConfig.ShellExtension.InterceptDragDrop"), true); -PROPERTY(PP_SHINTERCEPTKEYACTIONS, bool, _T("CHConfig.ShellExtension.ShowCommands.InterceptKeyboardActions"), true); -PROPERTY(PP_SHINTERCEPTCTXMENUACTIONS, bool, _T("CHConfig.ShellExtension.ShowCommands.InterceptDefaultContextMenuActions"), false); +PROPERTY(PP_SHINTERCEPTKEYACTIONS, bool, _T("CHConfig.ShellExtension.InterceptKeyboardActions"), true); +PROPERTY(PP_SHINTERCEPTCTXMENUACTIONS, bool, _T("CHConfig.ShellExtension.InterceptDefaultContextMenuActions"), false); // Invisible options PROPERTY_MINMAX(PP_LAST_UPDATE_TIMESTAMP, long long, _T("CHConfig.RuntimeState.LastCheckedForUpdates"), 0, 0, LLONG_MAX); @@ -233,20 +253,20 @@ typename PropData::value_type GetPropValue(const TConfig& rConfig) { typename PropData::value_type tValue; - rConfig.GetValue(PropData::GetPropertyName(), tValue, PropData::GetDefaultValue()); + rConfig.GetValue(CString(PropData::GetPropertyNamePrefix()) + PropData::GetPropertyName(), tValue, PropData::GetDefaultValue()); return tValue; } template bool GetPropValue(const TConfig& rConfig, typename PropData::value_type& rValue) { - return rConfig.GetValue(PropData::GetPropertyName(), rValue, PropData::GetDefaultValue()); + return rConfig.GetValue(CString(PropData::GetPropertyNamePrefix()) + PropData::GetPropertyName(), rValue, PropData::GetDefaultValue()); } template void SetPropValue(TConfig& rConfig, const typename PropData::value_type& rValue) { - rConfig.SetValue(PropData::GetPropertyName(), rValue); + rConfig.SetValue(CString(PropData::GetPropertyNamePrefix()) + PropData::GetPropertyName(), rValue); } #endif Index: src/ch/ClipboardMonitor.cpp =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/ClipboardMonitor.cpp (.../ClipboardMonitor.cpp) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/ClipboardMonitor.cpp (.../ClipboardMonitor.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -115,6 +115,9 @@ tTaskDefinition.SetOperationType(eOperation); // copy + // set the default options for task + GetConfig().ExtractSubConfig(BRANCH_TASK_SETTINGS, tTaskDefinition.GetConfiguration()); + EmptyClipboard(); CloseClipboard(); @@ -145,7 +148,7 @@ size_t stEntries = (stClipboardSize > 3) ? 2 : stClipboardSize; for(size_t stIndex = 0; stIndex < stEntries; stIndex++) { - dlg.m_bdData.strText += tTaskDefinition.GetSourcePathNameAt(stIndex) + _T("\n"); + dlg.m_bdData.strText += tTaskDefinition.GetSourcePathAt(stIndex) + _T("\n"); } // add ... @@ -191,8 +194,7 @@ pData->m_pTasks->Add(spTask); // write spTask to a file - spTask->Store(true); - spTask->Store(false); + spTask->Store(); // start processing spTask->BeginProcessing(); Index: src/ch/MainWnd.cpp =================================================================== diff -u -N -r3c3018d15591811e0b3cb35f43ceb31f4914f47e -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 3c3018d15591811e0b3cb35f43ceb31f4914f47e) +++ src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -366,7 +366,7 @@ case 1023: // autosave timer KillTimer(1023); - m_tasks.SaveProgress(); + m_tasks.SaveData(); SetTimer(1023, GetPropValue(GetConfig()), NULL); break; case 3245: @@ -507,10 +507,15 @@ tTaskDefinition.SetOperationType(bMove ? eOperation_Move : eOperation_Copy); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetCreateEmptyFiles(bOnlyCreate != FALSE); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetCreateOnlyDirectories(bForceDirectories != FALSE); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetIgnoreDirectories(bIgnoreDirs != FALSE); + // set the default options for task + GetConfig().ExtractSubConfig(BRANCH_TASK_SETTINGS, tTaskDefinition.GetConfiguration()); + // and override them with manual settings + SetTaskPropValue(tTaskDefinition.GetConfiguration(), bOnlyCreate != FALSE); + SetTaskPropValue(tTaskDefinition.GetConfiguration(), bForceDirectories != FALSE); + SetTaskPropValue(tTaskDefinition.GetConfiguration(), bIgnoreDirs != FALSE); + + // create task with the above definition CTaskPtr spTask = m_tasks.CreateTask(); spTask->SetTaskDefinition(tTaskDefinition); @@ -523,8 +528,7 @@ m_tasks.Add(spTask); // save state of a task - spTask->Store(true); - spTask->Store(false); + spTask->Store(); // add to task list and start processing spTask->BeginProcessing(); @@ -571,22 +575,25 @@ TTaskDefinition tTaskDefinition; - tTaskDefinition.SetOperationType((dlg.m_ccData.m_iOperation == 1) ? eOperation_Move : eOperation_Copy); - - tTaskDefinition.SetDestinationPath(dlg.m_ccData.m_strDestPath); - for (int iIndex = 0; iIndex < dlg.m_ccData.m_astrPaths.GetSize(); iIndex++) { tTaskDefinition.AddSourcePath(dlg.m_ccData.m_astrPaths.GetAt(iIndex)); } - // new task - CTaskPtr spTask = m_tasks.CreateTask(); + tTaskDefinition.SetDestinationPath(dlg.m_ccData.m_strDestPath); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetCreateEmptyFiles(dlg.m_ccData.m_bCreateStructure); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetCreateOnlyDirectories(dlg.m_ccData.m_bForceDirectories); - tTaskDefinition.GetConfiguration().GetCopyMoveConfig().SetIgnoreDirectories(dlg.m_ccData.m_bIgnoreFolders); + tTaskDefinition.SetOperationType((dlg.m_ccData.m_iOperation == 1) ? eOperation_Move : eOperation_Copy); + // set the default options for task + GetConfig().ExtractSubConfig(BRANCH_TASK_SETTINGS, tTaskDefinition.GetConfiguration()); + + // and override them with manual settings + SetTaskPropValue(tTaskDefinition.GetConfiguration(), dlg.m_ccData.m_bCreateStructure); + SetTaskPropValue(tTaskDefinition.GetConfiguration(), dlg.m_ccData.m_bForceDirectories); + SetTaskPropValue(tTaskDefinition.GetConfiguration(), dlg.m_ccData.m_bIgnoreFolders); + + // new task + CTaskPtr spTask = m_tasks.CreateTask(); spTask->SetTaskDefinition(tTaskDefinition); spTask->SetBufferSizes(&dlg.m_ccData.m_bsSizes); @@ -596,9 +603,8 @@ m_tasks.Add(spTask); // save - spTask->Store(true); - spTask->Store(false); - + spTask->Store(); + // store and start spTask->BeginProcessing(); } @@ -868,7 +874,7 @@ m_tasks.StopAllTasks(); // save - m_tasks.SaveProgress(); + m_tasks.SaveData(); // delete all tasks m_tasks.RemoveAll(); Index: src/ch/StatusDlg.cpp =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/StatusDlg.cpp (.../StatusDlg.cpp) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/StatusDlg.cpp (.../StatusDlg.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -316,7 +316,7 @@ { GetDlgItem(IDC_DESTINATION_STATIC)->SetWindowText(td.m_strDstPath); GetDlgItem(IDC_PRIORITY_STATIC)->SetWindowText(GetResManager().LoadString(IDS_PRIORITY0_STRING+PriorityToIndex(td.m_nPriority))); - GetDlgItem(IDC_ASSOCIATEDFILES__STATIC)->SetWindowText(td.m_strUniqueName + _T(".atd (.atp, .log)")); + GetDlgItem(IDC_ASSOCIATEDFILES__STATIC)->SetWindowText(td.m_strUniqueName); } // refresh m_spLastSelected @@ -771,14 +771,12 @@ if (!spTask) return; - unsigned long lResult = (unsigned long)(ShellExecute(this->m_hWnd, _T("open"), _T("notepad.exe"), - CString(spTask->GetTaskPath()) + spTask->GetTaskDefinition().GetTaskUniqueID() + _T(".log"), NULL, SW_SHOWNORMAL)); + unsigned long lResult = (unsigned long)(ShellExecute(this->m_hWnd, _T("open"), _T("notepad.exe"), spTask->GetRelatedPath(CTask::ePathType_TaskLogFile), NULL, SW_SHOWNORMAL)); if(lResult < 32) { - CString str = CString(spTask->GetTaskPath()) + spTask->GetTaskDefinition().GetTaskUniqueID()+_T(".log"); ictranslate::CFormat fmt(GetResManager().LoadString(IDS_SHELLEXECUTEERROR_STRING)); fmt.SetParam(_t("%errno"), lResult); - fmt.SetParam(_t("%path"), str); + fmt.SetParam(_t("%path"), spTask->GetRelatedPath(CTask::ePathType_TaskLogFile)); AfxMessageBox(fmt); } } Index: src/ch/TConfig.cpp =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/TConfig.cpp (.../TConfig.cpp) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/TConfig.cpp (.../TConfig.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -67,22 +67,53 @@ // class TConfig TConfig::TConfig() : - m_bDelayedEnabled(false) + m_bDelayedEnabled(false), + m_bModified(false) { } +TConfig::TConfig(const TConfig& rSrc) : + m_bDelayedEnabled(false), + m_bModified(rSrc.m_bModified) +{ + boost::shared_lock lock(rSrc.m_lock); + + m_propTree = rSrc.m_propTree; + m_strFilePath = rSrc.m_strFilePath; +} + +TConfig& TConfig::operator=(const TConfig& rSrc) +{ + if(this != &rSrc) + { + boost::shared_lock src_lock(rSrc.m_lock); + boost::unique_lock lock(m_lock); + + m_propTree = rSrc.m_propTree; + m_bModified = rSrc.m_bModified; + m_strFilePath = rSrc.m_strFilePath; + m_bDelayedEnabled = false; + m_setDelayedNotifications.clear(); + } + + return *this; +} + TConfig::~TConfig() { } // read/write void TConfig::Read(const CString& strFile) { - m_strFilePath = strFile; - std::wifstream ifs(m_strFilePath, ios_base::in); - boost::unique_lock lock(m_lock); + // Note: we need to store filename for later use BEFORE trying to open a file + // since it might be nonexistent, but we still would like to store config to this file later + ClearNL(); // also clears m_bModified + m_strFilePath = strFile; + + std::wifstream ifs(m_strFilePath, ios_base::in); try { boost::property_tree::xml_parser::read_xml(ifs, m_propTree); @@ -94,18 +125,60 @@ } } -void TConfig::Write() +void TConfig::Write(bool bOnlyIfModified) { - std::wofstream ofs(m_strFilePath, ios_base::out); + boost::shared_lock lock(m_lock); + if(!bOnlyIfModified || m_bModified) + { + std::wofstream ofs(m_strFilePath, ios_base::out); + boost::property_tree::xml_parser::write_xml(ofs, m_propTree); + m_bModified = false; + } +} + +void TConfig::SetFilePath(const CString& strPath) +{ + boost::unique_lock lock(m_lock); + if(m_strFilePath != strPath) + { + m_strFilePath = strPath; + m_bModified = true; // since the path is modified, we can only assume that stuff needs to be written into it regardless of the current modification state + } +} + +bool TConfig::IsModified() const +{ boost::shared_lock lock(m_lock); - boost::property_tree::xml_parser::write_xml(ofs, m_propTree); + return m_bModified; } +void TConfig::MarkAsModified() +{ + boost::unique_lock lock(m_lock); + m_bModified = true; +} + +void TConfig::MarkAsNotModified() +{ + boost::unique_lock lock(m_lock); + m_bModified = false; +} + void TConfig::Clear() { boost::unique_lock lock(m_lock); + + ClearNL(); +} + +void TConfig::ClearNL() +{ m_propTree.clear(); + m_bModified = false; + m_setDelayedNotifications.clear(); + m_bDelayedEnabled = false; + m_strFilePath.Empty(); } // value setting/retrieval @@ -132,8 +205,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, bool bValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, bValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, bValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -163,8 +240,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, int iValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, iValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, iValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -193,8 +274,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, unsigned int uiValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, uiValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, uiValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -223,8 +308,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, long long llValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, llValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, llValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -253,8 +342,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, unsigned long long ullValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, ullValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, ullValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -283,8 +376,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, double dValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, dValue); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, dValue); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -314,8 +411,12 @@ TConfig& TConfig::SetValue(PCTSTR pszPropName, const CString& strValue) { - boost::unique_lock lock(m_lock); - m_propTree.put(pszPropName, std::wstring(strValue)); + // separate scope for mutex (to avoid calling notifier inside critical section) + { + boost::unique_lock lock(m_lock); + m_propTree.put(pszPropName, std::wstring(strValue)); + m_bModified = true; + } SendNotification(pszPropName); return *this; @@ -359,26 +460,42 @@ void TConfig::SetValue(PCTSTR pszPropName, const std::vector& rvValues) { - boost::unique_lock lock(m_lock); - m_propTree.erase(pszPropName); - BOOST_FOREACH(const CString& strValue, rvValues) + // separate scope for mutex (to avoid calling notifier inside critical section) { - m_propTree.add(pszPropName, (PCTSTR)strValue); + boost::unique_lock lock(m_lock); + m_propTree.erase(pszPropName); + BOOST_FOREACH(const CString& strValue, rvValues) + { + m_propTree.add(pszPropName, (PCTSTR)strValue); + } + + m_bModified = true; } + SendNotification(pszPropName); } // extraction of subtrees void TConfig::ExtractSubConfig(PCTSTR pszSubTreeName, TConfig& rSubConfig) const { - boost::unique_lock dst_lock(m_lock); - rSubConfig.Clear(); + boost::unique_lock dst_lock(rSubConfig.m_lock); + rSubConfig.ClearNL(); boost::shared_lock lock(m_lock); rSubConfig.m_propTree = m_propTree.get_child(pszSubTreeName); } +void TConfig::PutSubConfig(PCTSTR pszSubTreeName, const TConfig& rSubConfig) +{ + boost::unique_lock lock(m_lock); + boost::shared_lock src_lock(rSubConfig.m_lock); + + m_propTree.put_child(pszSubTreeName, rSubConfig.m_propTree); + + m_bModified = true; +} + void TConfig::ConnectToNotifier(void (*pfnCallback)(const std::set&, void*), void* pParam) { m_notifier.connect(TConfigNotifier(pfnCallback, pParam)); @@ -391,38 +508,69 @@ void TConfig::DelayNotifications() { + boost::unique_lock lock(m_lock); m_bDelayedEnabled = true; } void TConfig::ResumeNotifications() { - if(m_bDelayedEnabled) + std::set setNotifications; + + // separate scope for shared mutex (to avoid calling notifier inside critical section) { - m_bDelayedEnabled = false; - if(!m_setDelayedNotifications.empty()) + boost::upgrade_lock lock(m_lock); + if(m_bDelayedEnabled) { - SendNotification(m_setDelayedNotifications); - m_setDelayedNotifications.clear(); + m_bDelayedEnabled = false; + if(!m_setDelayedNotifications.empty()) + { + setNotifications = m_setDelayedNotifications; + + boost::upgrade_to_unique_lock upgraded_lock(lock); + m_setDelayedNotifications.clear(); + } } } + + // NOTE: no locking here! + if(!setNotifications.empty()) + SendNotification(setNotifications); } void TConfig::SendNotification(const std::set& rsetInfo) { - if(m_bDelayedEnabled) - m_setDelayedNotifications.insert(rsetInfo.begin(), rsetInfo.end()); - else - m_notifier(rsetInfo); + // separate scope for shared mutex (to avoid calling notifier inside critical section) + { + boost::upgrade_lock lock(m_lock); + if(m_bDelayedEnabled) + { + boost::upgrade_to_unique_lock upgraded_lock(lock); + + m_setDelayedNotifications.insert(rsetInfo.begin(), rsetInfo.end()); + return; + } + } + + // NOTE: we don't lock here + m_notifier(rsetInfo); } void TConfig::SendNotification(PCTSTR pszInfo) { - if(m_bDelayedEnabled) - m_setDelayedNotifications.insert(pszInfo); - else + // separate scope for shared mutex (to avoid calling notifier inside critical section) { - std::set setData; - setData.insert(pszInfo); - m_notifier(setData); + boost::upgrade_lock lock(m_lock); + if(m_bDelayedEnabled) + { + boost::upgrade_to_unique_lock upgraded_lock(lock); + + m_setDelayedNotifications.insert(pszInfo); + return; + } } + + // NOTE: we don't lock here + std::set setData; + setData.insert(pszInfo); + m_notifier(setData); } Index: src/ch/TConfig.h =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/TConfig.h (.../TConfig.h) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/TConfig.h (.../TConfig.h) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -29,6 +29,7 @@ #include #pragma warning(pop) +// class defines configuration change notification record; not to be used outside class TConfigNotifier { public: @@ -46,18 +47,29 @@ void* m_pParam; }; +// class for handling configuration settings class TConfig { public: TConfig(); + TConfig(const TConfig& rSrc); ~TConfig(); + TConfig& operator=(const TConfig& rSrc); + + void Clear(); + // read/write void Read(const CString& strFile); - void Write(); + void Write(bool bOnlyIfModified = false); - void Clear(); + void SetFilePath(const CString& strPath); + // Modifications management + bool IsModified() const; + void MarkAsModified(); + void MarkAsNotModified(); + // value setting/retrieval bool GetBool(PCTSTR pszPropName, bool bDefault) const; bool GetValue(PCTSTR pszPropName, bool& bValue, bool bDefault) const; @@ -93,6 +105,7 @@ // extraction of subtrees void ExtractSubConfig(PCTSTR pszSubTreeName, TConfig& rSubConfig) const; + void PutSubConfig(PCTSTR pszSubTreeName, const TConfig& rSubConfig); // property change notification void ConnectToNotifier(void (*pfnCallback)(const std::set&, void*), void* pParam); @@ -105,6 +118,8 @@ void SendNotification(const std::set& rsetInfo); void SendNotification(PCTSTR pszInfo); + void ClearNL(); + private: boost::property_tree::wiptree m_propTree; CString m_strFilePath; @@ -113,6 +128,8 @@ std::set m_setDelayedNotifications; bool m_bDelayedEnabled; + bool m_bModified; ///< Modification state - cleared when saving + mutable boost::shared_mutex m_lock; }; Index: src/ch/TTaskConfiguration.cpp =================================================================== diff -u -N --- src/ch/TTaskConfiguration.cpp (revision 044d0e17cdedf3055202486a2235e1a3c8dd6e56) +++ src/ch/TTaskConfiguration.cpp (revision 0) @@ -1,295 +0,0 @@ -// ============================================================================ -// Copyright (C) 2001-2010 by Jozef Starosczyk -// ixen@copyhandler.com -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU Library General Public License -// (version 2) as published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this program; if not, write to the -// Free Software Foundation, Inc., -// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// ============================================================================ -/// @file TTaskConfiguration.cpp -/// @date 2010/09/18 -/// @brief Contains implementation of class TTaskConfiguration. -// ============================================================================ -#include "stdafx.h" -#include "TTaskConfiguration.h" - - -/////////////////////////////////////////////////////////////////////////// -// TSubTaskCommonConfig - -TSubTaskCommonConfig::TSubTaskCommonConfig() : - m_nPriority(THREAD_PRIORITY_NORMAL), - m_bDeleteAllFilesAfterAllCopyings(true), - m_bIgnoreReadOnlyAttributes(false) -{ -} - -TSubTaskCommonConfig::TSubTaskCommonConfig(const TSubTaskCommonConfig& rSrc) : - m_nPriority(THREAD_PRIORITY_NORMAL), - m_bDeleteAllFilesAfterAllCopyings(true), - m_bIgnoreReadOnlyAttributes(false) -{ - *this = rSrc; -} - -TSubTaskCommonConfig::~TSubTaskCommonConfig() -{ -} - -TSubTaskCommonConfig& TSubTaskCommonConfig::operator=(const TSubTaskCommonConfig& rSrc) -{ - if(this != &rSrc) - { - boost::shared_lock src_lock(rSrc.m_lock); - boost::unique_lock lock(m_lock); - - m_nPriority = rSrc.m_nPriority; - m_bDeleteAllFilesAfterAllCopyings = rSrc.m_bDeleteAllFilesAfterAllCopyings; - m_bIgnoreReadOnlyAttributes = rSrc.m_bIgnoreReadOnlyAttributes; - } - - return *this; -} - -void TSubTaskCommonConfig::SetPriority(int iPriority) -{ - boost::unique_lock lock(m_lock); - m_nPriority = iPriority; -} - -int TSubTaskCommonConfig::GetPriority() const -{ - boost::shared_lock lock(m_lock); - return m_nPriority; -} - -void TSubTaskCommonConfig::SetDeleteAllFilesAfterAllCopyings(bool bSeparateDelete) -{ - boost::unique_lock lock(m_lock); - m_bDeleteAllFilesAfterAllCopyings = bSeparateDelete; -} - -bool TSubTaskCommonConfig::GetDeleteAllFilesAfterAllCopyings() const -{ - boost::shared_lock lock(m_lock); - return m_bDeleteAllFilesAfterAllCopyings; -} - -void TSubTaskCommonConfig::SetIgnoreReadOnlyAttributes(bool bIgnoreReadOnlyAttributes) -{ - boost::unique_lock lock(m_lock); - m_bIgnoreReadOnlyAttributes = bIgnoreReadOnlyAttributes; -} - -bool TSubTaskCommonConfig::GetIgnoreReadOnlyAttributes() const -{ - boost::shared_lock lock(m_lock); - return m_bIgnoreReadOnlyAttributes; -} - -//////////////////////////////////////////////////////////////////////////// -// class TSubTaskScanDirectoriesConfig - -TSubTaskScanDirectoriesConfig::TSubTaskScanDirectoriesConfig() : - m_afFilters() -{ -} - -TSubTaskScanDirectoriesConfig::TSubTaskScanDirectoriesConfig(const TSubTaskScanDirectoriesConfig& rSrc) : - m_afFilters() -{ - *this = rSrc; -} - -TSubTaskScanDirectoriesConfig::~TSubTaskScanDirectoriesConfig() -{ -} - -TSubTaskScanDirectoriesConfig& TSubTaskScanDirectoriesConfig::operator=(const TSubTaskScanDirectoriesConfig& rSrc) -{ - if(this != &rSrc) - { - boost::shared_lock src_lock(rSrc.m_lock); - boost::unique_lock lock(m_lock); - - m_afFilters = rSrc.m_afFilters; - } - - return *this; -} - -void TSubTaskScanDirectoriesConfig::SetFilters(const CFiltersArray& rFilters) -{ - boost::unique_lock lock(m_lock); - m_afFilters = rFilters; -} - -//////////////////////////////////////////////////////////////////////////// -// class TSubTaskCopyMoveConfig - -TSubTaskCopyMoveConfig::TSubTaskCopyMoveConfig() : - m_bDisableSystemBuffering(false), - m_ullMinSizeToDisableBuffering(0), - m_bPreserveFileDateTime(false), - m_bPreserveFileAttributes(false), - m_bIgnoreDirectories(false), - m_bCreateEmptyFiles(false), - m_bCreateOnlyDirectories(false) -{ - m_bsSizes.m_uiDefaultSize = 0; - m_bsSizes.m_uiOneDiskSize = 0; - m_bsSizes.m_uiTwoDisksSize = 0; - m_bsSizes.m_uiCDSize = 0; - m_bsSizes.m_uiLANSize = 0; - m_bsSizes.m_bOnlyDefault = false; -} - -TSubTaskCopyMoveConfig::TSubTaskCopyMoveConfig(const TSubTaskCopyMoveConfig& rSrc) : - m_bDisableSystemBuffering(false), - m_ullMinSizeToDisableBuffering(0), - m_bPreserveFileDateTime(false), - m_bPreserveFileAttributes(false), - m_bIgnoreDirectories(false), - m_bCreateEmptyFiles(false), - m_bCreateOnlyDirectories(false) -{ - *this = rSrc; -} - -TSubTaskCopyMoveConfig::~TSubTaskCopyMoveConfig() -{ -} - -TSubTaskCopyMoveConfig& TSubTaskCopyMoveConfig::operator=(const TSubTaskCopyMoveConfig& rSrc) -{ - if(this != &rSrc) - { - m_bDisableSystemBuffering = rSrc.m_bDisableSystemBuffering; - m_ullMinSizeToDisableBuffering = rSrc.m_ullMinSizeToDisableBuffering; - m_bPreserveFileDateTime = rSrc.m_bPreserveFileDateTime; - m_bPreserveFileAttributes = rSrc.m_bPreserveFileAttributes; - m_bIgnoreDirectories = rSrc.m_bIgnoreDirectories; - m_bCreateEmptyFiles = rSrc.m_bCreateEmptyFiles; - m_bCreateOnlyDirectories = rSrc.m_bCreateOnlyDirectories; - m_bsSizes = rSrc.m_bsSizes; - } - - return *this; -} - -void TSubTaskCopyMoveConfig::SetDisableSystemBuffering(bool bDisableBuffering) -{ - boost::unique_lock lock(m_lock); - m_bDisableSystemBuffering = bDisableBuffering; -} - -bool TSubTaskCopyMoveConfig::GetDisableSystemBuffering() const -{ - boost::shared_lock lock(m_lock); - return m_bDisableSystemBuffering; -} - -void TSubTaskCopyMoveConfig::SetMinSizeToDisableBuffering(unsigned long long ullMinSize) -{ - boost::unique_lock lock(m_lock); - m_ullMinSizeToDisableBuffering = ullMinSize; -} - -unsigned long long TSubTaskCopyMoveConfig::GetMinSizeToDisableBuffering() const -{ - boost::shared_lock lock(m_lock); - return m_ullMinSizeToDisableBuffering; -} - -void TSubTaskCopyMoveConfig::SetPreserveFileDateTime(bool bPreserve) -{ - boost::unique_lock lock(m_lock); - m_bPreserveFileDateTime = bPreserve; -} - -bool TSubTaskCopyMoveConfig::GetPreserveFileDateTime() const -{ - boost::shared_lock lock(m_lock); - return m_bPreserveFileDateTime; -} - -void TSubTaskCopyMoveConfig::SetPreserveFileAttributes(bool bPreserve) -{ - boost::unique_lock lock(m_lock); - m_bPreserveFileAttributes = bPreserve; -} - -bool TSubTaskCopyMoveConfig::GetPreserveFileAttributes() const -{ - boost::shared_lock lock(m_lock); - return m_bPreserveFileAttributes; -} - -void TSubTaskCopyMoveConfig::SetBufferSizes(const BUFFERSIZES& bsSizes) -{ - boost::unique_lock lock(m_lock); - m_bsSizes = bsSizes; -} - -BUFFERSIZES TSubTaskCopyMoveConfig::GetBufferSizes() const -{ - boost::shared_lock lock(m_lock); - return m_bsSizes; -} - -void TSubTaskCopyMoveConfig::SetIgnoreDirectories(bool bIgnore) -{ - boost::unique_lock lock(m_lock); - m_bIgnoreDirectories = bIgnore; -} - -bool TSubTaskCopyMoveConfig::GetIgnoreDirectories() const -{ - boost::shared_lock lock(m_lock); - return m_bIgnoreDirectories; -} - -void TSubTaskCopyMoveConfig::SetCreateEmptyFiles(bool bCreateEmpty) -{ - boost::unique_lock lock(m_lock); - m_bCreateEmptyFiles = bCreateEmpty; -} - -bool TSubTaskCopyMoveConfig::GetCreateEmptyFiles() const -{ - boost::shared_lock lock(m_lock); - return m_bCreateEmptyFiles; -} - -void TSubTaskCopyMoveConfig::SetCreateOnlyDirectories(bool bCreateOnlyDirs) -{ - boost::unique_lock lock(m_lock); - m_bCreateOnlyDirectories = bCreateOnlyDirs; -} - -bool TSubTaskCopyMoveConfig::GetCreateOnlyDirectories() const -{ - boost::shared_lock lock(m_lock); - return m_bCreateOnlyDirectories; -} - -//////////////////////////////////////////////////////////////////////////// -// class TTaskConfiguration - -TTaskConfiguration::TTaskConfiguration() -{ -} - -TTaskConfiguration::~TTaskConfiguration() -{ -} Index: src/ch/TTaskConfiguration.h =================================================================== diff -u -N -r98791237b8511ff19aa54dc3c6901222287d9914 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/TTaskConfiguration.h (.../TTaskConfiguration.h) (revision 98791237b8511ff19aa54dc3c6901222287d9914) +++ src/ch/TTaskConfiguration.h (.../TTaskConfiguration.h) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -23,233 +23,97 @@ #ifndef __TTASKCONFIGURATION_H__ #define __TTASKCONFIGURATION_H__ -#include "FileInfo.h" -#include "FileFilter.h" -#include "DataBuffer.h" +class TConfig; -/////////////////////////////////////////////////////////////////////////// -// TSubTaskCommonConfig -class TSubTaskCommonConfig +enum ETaskOptions { -public: - TSubTaskCommonConfig(); - TSubTaskCommonConfig(const TSubTaskCommonConfig& rSrc); - ~TSubTaskCommonConfig(); + eTO_UseOnlyDefaultBuffer, + eTO_DefaultBufferSize, + eTO_OneDiskBufferSize, + eTO_TwoDisksBufferSize, + eTO_CDBufferSize, + eTO_LANBufferSize, + eTO_DisableBuffering, + eTO_DisableBufferingMinSize, - TSubTaskCommonConfig& operator=(const TSubTaskCommonConfig& rSrc); + eTO_SetDestinationAttributes, + eTO_SetDestinationDateTime, + eTO_ProtectReadOnlyFiles, + eTO_ScanDirectoriesBeforeBlocking, + eTO_ThreadPriority, + eTO_DisablePriorityBoost, + eTO_DeleteInSeparateSubTask, - void SetPriority(int iPriority); - int GetPriority() const; - - void SetDeleteAllFilesAfterAllCopyings(bool bSeparateDelete); - bool GetDeleteAllFilesAfterAllCopyings() const; - - void SetIgnoreReadOnlyAttributes(bool bIgnoreReadOnlyAttributes); - bool GetIgnoreReadOnlyAttributes() const; - - template - void load(Archive& ar, unsigned int /*uiVersion*/) - { - boost::unique_lock lock(m_lock); - - ar >> m_nPriority; - ar >> m_bDeleteAllFilesAfterAllCopyings; - ar >> m_bIgnoreReadOnlyAttributes; - } - - template - void save(Archive& ar, unsigned int /*uiVersion*/) const - { - boost::shared_lock lock(m_lock); - - ar << m_nPriority; - ar << m_bDeleteAllFilesAfterAllCopyings; - ar << m_bIgnoreReadOnlyAttributes; - } - - BOOST_SERIALIZATION_SPLIT_MEMBER(); - -private: - int m_nPriority; // task priority (really processing thread priority) - bool m_bDeleteAllFilesAfterAllCopyings; ///< Delete mode; true means that deleting files is a separate sub-operation launched after copying, false states that file is deleted immediately after being copied - bool m_bIgnoreReadOnlyAttributes; // ignore read-only attributes on files (delete/overwrite) -> this should be handled by feedback requests probably - - mutable boost::shared_mutex m_lock; + eTO_CreateEmptyFiles, + eTO_CreateDirectoriesRelativeToRoot, + eTO_IgnoreDirectories, }; -/////////////////////////////////////////////////////////////////////////// -// TSubTaskScanDirectoriesConfig +///////////////////////////////////////////////////////////////////////////////////////////// +// Properties definitions -class TSubTaskScanDirectoriesConfig -{ -public: - TSubTaskScanDirectoriesConfig(); - TSubTaskScanDirectoriesConfig(const TSubTaskScanDirectoriesConfig& rSrc); - ~TSubTaskScanDirectoriesConfig(); +template struct TaskPropData; - TSubTaskScanDirectoriesConfig& operator=(const TSubTaskScanDirectoriesConfig& rSrc); +#define TASK_PROPERTY(enum_id, val_type, val_name, def_value)\ + template<> struct TaskPropData\ +{\ + typedef val_type value_type;\ + static value_type GetDefaultValue() { return def_value; }\ + static const wchar_t* GetPropertyName() { return val_name; }\ +} - // filtering rules - void SetFilters(const CFiltersArray& rFilters); - const CFiltersArray& GetFilters() const { return m_afFilters; } +#define TASK_PROPERTY_MINMAX(enum_id, val_type, val_name, def_value, min_val, max_val)\ + template<> struct TaskPropData\ +{\ + typedef val_type value_type;\ + static value_type GetDefaultValue() { return def_value; }\ + static const wchar_t* GetPropertyName() { return val_name; }\ +} - template - void load(Archive& ar, unsigned int /*uiVersion*/) - { - boost::unique_lock lock(m_lock); - ar >> m_afFilters; - } +TASK_PROPERTY(eTO_UseOnlyDefaultBuffer, bool, _T("Buffer.UseOnlyDefaultBuffer"), false); +TASK_PROPERTY_MINMAX(eTO_DefaultBufferSize, unsigned int, _T("Buffer.DefaultBufferSize"), 2097152, 1, 0xffffffff); +TASK_PROPERTY_MINMAX(eTO_OneDiskBufferSize, unsigned int, _T("Buffer.OnePhysicalDiskSize"), 4194304, 1, 0xffffffff); +TASK_PROPERTY_MINMAX(eTO_TwoDisksBufferSize, unsigned int, _T("Buffer.TwoPhysicalDisksSize"), 524288, 1, 0xffffffff); +TASK_PROPERTY_MINMAX(eTO_CDBufferSize, unsigned int, _T("Buffer.CDSize"), 262144, 1, 0xffffffff); +TASK_PROPERTY_MINMAX(eTO_LANBufferSize, unsigned int, _T("Buffer.LANSize"), 131072, 1, 0xffffffff); - template - void save(Archive& ar, unsigned int /*uiVersion*/) const - { - boost::shared_lock lock(m_lock); - ar << m_afFilters; - } +TASK_PROPERTY(eTO_DisableBuffering, bool, _T("Operation.Buffering.DisableBufferingForLargeFiles"), true); +TASK_PROPERTY_MINMAX(eTO_DisableBufferingMinSize, int, _T("Operation.Buffering.MinSizeOfFileToDisableBuffering"), 2097152, 1, 0xffffffff); - BOOST_SERIALIZATION_SPLIT_MEMBER(); +TASK_PROPERTY(eTO_SetDestinationAttributes, bool, _T("Operation.SetDestinationAttributes"), true); +TASK_PROPERTY(eTO_SetDestinationDateTime, bool, _T("Operation.SetDestinationTime"), true); +TASK_PROPERTY(eTO_ProtectReadOnlyFiles, bool, _T("Operation.ProtectReadOnlyFiles"), true); +TASK_PROPERTY(eTO_ScanDirectoriesBeforeBlocking, bool, _T("Operation.ScanForFilesBeforeBlocking"), true); -private: - CFiltersArray m_afFilters; // filtering settings for files (will be filtered according to the rules inside when searching for files) +TASK_PROPERTY(eTO_ThreadPriority, int, _T("Operation.Thread.Priority"), THREAD_PRIORITY_NORMAL); +TASK_PROPERTY(eTO_DisablePriorityBoost, bool, _T("Operation.Thread.DisablePriorityBoost"), false); - mutable boost::shared_mutex m_lock; -}; +TASK_PROPERTY(eTO_DeleteInSeparateSubTask, bool, _T("Operation.DeleteFilesInSeparateOperation"), true); -/////////////////////////////////////////////////////////////////////////// -// TSubTaskCopyMoveConfig +TASK_PROPERTY(eTO_CreateEmptyFiles, bool, _T("Operation.CreateEmptyFiles"), false); +TASK_PROPERTY(eTO_CreateDirectoriesRelativeToRoot, bool, _T("Operation.CreateDirectoriesRelativeToRoot"), false); +TASK_PROPERTY(eTO_IgnoreDirectories, bool, _T("Operation.IgnoreDirectories"), false); -class TSubTaskCopyMoveConfig +///////////////////////////////////////////////////////////////////////////////////////////// +// Properties retrieval +template +typename TaskPropData::value_type GetTaskPropValue(const TConfig& rConfig) { -public: - TSubTaskCopyMoveConfig(); - TSubTaskCopyMoveConfig(const TSubTaskCopyMoveConfig& rSrc); - ~TSubTaskCopyMoveConfig(); + typename TaskPropData::value_type tValue; + rConfig.GetValue(TaskPropData::GetPropertyName(), tValue, TaskPropData::GetDefaultValue()); + return tValue; +} - TSubTaskCopyMoveConfig& operator=(const TSubTaskCopyMoveConfig& rSrc); - - void SetDisableSystemBuffering(bool bDisableBuffering); - bool GetDisableSystemBuffering() const; - - void SetMinSizeToDisableBuffering(unsigned long long ullMinSize); - unsigned long long GetMinSizeToDisableBuffering() const; - - void SetPreserveFileDateTime(bool bPreserve); - bool GetPreserveFileDateTime() const; - - void SetPreserveFileAttributes(bool bPreserve); - bool GetPreserveFileAttributes() const; - - void SetBufferSizes(const BUFFERSIZES& bsSizes); - BUFFERSIZES GetBufferSizes() const; - - void SetIgnoreDirectories(bool bIgnore); - bool GetIgnoreDirectories() const; - - void SetCreateEmptyFiles(bool bCreateEmpty); - bool GetCreateEmptyFiles() const; - - void SetCreateOnlyDirectories(bool bCreateOnlyDirs); - bool GetCreateOnlyDirectories() const; - - template - void load(Archive& ar, unsigned int /*uiVersion*/) - { - boost::unique_lock lock(m_lock); - - ar & m_bDisableSystemBuffering; - ar & m_ullMinSizeToDisableBuffering; - - ar & m_bPreserveFileDateTime; - ar & m_bPreserveFileAttributes; - - ar & m_bsSizes; - - ar & m_bIgnoreDirectories; - ar & m_bCreateEmptyFiles; - ar & m_bCreateOnlyDirectories; - } - - template - void save(Archive& ar, unsigned int /*uiVersion*/) const - { - boost::shared_lock lock(m_lock); - - ar & m_bDisableSystemBuffering; - ar & m_ullMinSizeToDisableBuffering; - - ar & m_bPreserveFileDateTime; - ar & m_bPreserveFileAttributes; - - ar & m_bsSizes; - - ar & m_bIgnoreDirectories; - ar & m_bCreateEmptyFiles; - ar & m_bCreateOnlyDirectories; - } - - BOOST_SERIALIZATION_SPLIT_MEMBER(); - -private: - bool m_bDisableSystemBuffering; ///< Disables system buffering of files - unsigned long long m_ullMinSizeToDisableBuffering; ///< Minimal file size to disable system buffering - - bool m_bPreserveFileDateTime; - bool m_bPreserveFileAttributes; - - BUFFERSIZES m_bsSizes; // sizes of buffers used to copy - - bool m_bIgnoreDirectories; - bool m_bCreateEmptyFiles; - bool m_bCreateOnlyDirectories; - - mutable boost::shared_mutex m_lock; -}; - -/////////////////////////////////////////////////////////////////////////// -// TSubTaskDeleteConfig - -/* -class TSubTaskDeleteConfig +template +bool GetTaskPropValue(const TConfig& rConfig, typename TaskPropData::value_type& rValue) { -private: - mutable boost::shared_mutex m_lock; -}; -*/ + return rConfig.GetValue(TaskPropData::GetPropertyName(), rValue, TaskPropData::GetDefaultValue()); +} -/////////////////////////////////////////////////////////////////////////// -// TTaskConfiguration - -class TTaskConfiguration +template +void SetTaskPropValue(TConfig& rConfig, const typename TaskPropData::value_type& rValue) { -public: - TTaskConfiguration(); - ~TTaskConfiguration(); + rConfig.SetValue(TaskPropData::GetPropertyName(), rValue); +} - const TSubTaskCommonConfig& GetCommonConfig() const { return m_tCommonConfig; } - TSubTaskCommonConfig& GetCommonConfig() { return m_tCommonConfig; } - - const TSubTaskScanDirectoriesConfig& GetScanDirectoriesConfig() const { return m_tScanDirectoriesConfig; } - TSubTaskScanDirectoriesConfig& GetScanDirectoriesConfig() { return m_tScanDirectoriesConfig; } - - const TSubTaskCopyMoveConfig& GetCopyMoveConfig() const { return m_tCopyMoveConfig; } - TSubTaskCopyMoveConfig& GetCopyMoveConfig() { return m_tCopyMoveConfig; } - - // const TSubTaskDeleteConfig& GetDeleteConfig() const { return m_tDeleteConfig; } - - template - void serialize(Archive& ar, unsigned int /*uiVersion*/) - { - ar & m_tCommonConfig; - ar & m_tScanDirectoriesConfig; - ar & m_tCopyMoveConfig; -// ar & m_tDeleteConfig; - } - -private: - TSubTaskCommonConfig m_tCommonConfig; - TSubTaskScanDirectoriesConfig m_tScanDirectoriesConfig; - TSubTaskCopyMoveConfig m_tCopyMoveConfig; -// TSubTaskDeleteConfig m_tDeleteConfig; -}; - #endif Index: src/ch/TTaskDefinition.cpp =================================================================== diff -u -N -rca1933ef07e18d939449e4878eca5cc81cc73f3f -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/TTaskDefinition.cpp (.../TTaskDefinition.cpp) (revision ca1933ef07e18d939449e4878eca5cc81cc73f3f) +++ src/ch/TTaskDefinition.cpp (.../TTaskDefinition.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -28,81 +28,99 @@ #include "TTaskDefinition.h" TTaskDefinition::TTaskDefinition() : - m_bNeedsSaving(false), + m_bModified(false), m_strTaskUniqueID() { boost::uuids::random_generator gen; boost::uuids::uuid u = gen(); - m_strTaskUniqueID = boost::lexical_cast(u); + m_strTaskUniqueID = boost::lexical_cast(u).c_str(); } +TTaskDefinition::TTaskDefinition(const TTaskDefinition& rSrc) : + m_strTaskUniqueID(rSrc.m_strTaskUniqueID), + m_vSourcePaths(rSrc.m_vSourcePaths), + m_strDestinationPath(rSrc.m_strDestinationPath), + m_tOperationPlan(rSrc.m_tOperationPlan), + m_tConfiguration(rSrc.m_tConfiguration), + m_bModified(rSrc.m_bModified) +{ +} + TTaskDefinition::~TTaskDefinition() { } -// initialize object with data (get/set, from cfg file?, from string(cmd line options)) -void TTaskDefinition::AddSourcePath(const CString& strPath) +TTaskDefinition& TTaskDefinition::operator=(const TTaskDefinition& rSrc) { - CClipboardEntryPtr spEntry(boost::make_shared()); - spEntry->SetPath(strPath); + if(this != &rSrc) + { + m_strTaskUniqueID = rSrc.m_strTaskUniqueID; + m_vSourcePaths = rSrc.m_vSourcePaths; + m_strDestinationPath = rSrc.m_strDestinationPath; + m_tOperationPlan = rSrc.m_tOperationPlan; + m_tConfiguration = rSrc.m_tConfiguration; + m_bModified = rSrc.m_bModified; + } - m_arrSourcePaths.Add(spEntry); + return *this; } -CString TTaskDefinition::GetSourcePathNameAt(size_t stIndex) const +// Task unique id +CString TTaskDefinition::GetTaskUniqueID() const { - CClipboardEntryPtr spEntry = m_arrSourcePaths.GetAt(stIndex); - if(spEntry) - return spEntry->GetPath(); - return CString(); + return m_strTaskUniqueID; } -CClipboardEntryPtr TTaskDefinition::GetSourcePathAt(size_t stIndex) const +// Source paths +// initialize object with data (get/set, from cfg file?, from string(cmd line options)) +void TTaskDefinition::AddSourcePath(const CString& strPath) { - CClipboardEntryPtr spEntry = m_arrSourcePaths.GetAt(stIndex); - return spEntry; + m_vSourcePaths.push_back(strPath); + m_bModified = true; } +CString TTaskDefinition::GetSourcePathAt(size_t stIndex) const +{ + return m_vSourcePaths.at(stIndex); +} + size_t TTaskDefinition::GetSourcePathCount() const { - return m_arrSourcePaths.GetSize(); + return m_vSourcePaths.size(); } void TTaskDefinition::ClearSourcePaths() { - m_arrSourcePaths.RemoveAll(); + m_vSourcePaths.clear(); + m_bModified = true; } -const CClipboardArray& TTaskDefinition::GetSourcePaths() const +const std::vector& TTaskDefinition::GetSourcePaths() const { - return m_arrSourcePaths; + return m_vSourcePaths; } +// Destination path void TTaskDefinition::SetDestinationPath(const CString& strPath) { - m_tDestinationPath.SetPath(strPath); + m_strDestinationPath = strPath; + if(m_strDestinationPath.Right(1) != _T("\\")) + m_strDestinationPath += _T("\\"); + m_bModified = true; } CString TTaskDefinition::GetDestinationPath() const { - return m_tDestinationPath.GetPath(); + return m_strDestinationPath; } -const CDestPath& TTaskDefinition::GetDestPath() const -{ - return m_tDestinationPath; -} - +// Operation type void TTaskDefinition::SetOperationType(EOperationType eOperation) { m_tOperationPlan.SetOperationType(eOperation); + m_bModified = true; } -CString TTaskDefinition::GetTaskUniqueID() const -{ - return m_strTaskUniqueID.c_str(); -} - EOperationType TTaskDefinition::GetOperationType() const { return m_tOperationPlan.GetOperationType(); @@ -113,12 +131,87 @@ return m_tOperationPlan; } -TTaskConfiguration& TTaskDefinition::GetConfiguration() +// Task configuration +void TTaskDefinition::SetConfig(const TConfig& rConfig) { - return m_tOperationConfiguration; + m_tConfiguration = rConfig; + m_bModified = true; } -const TTaskConfiguration& TTaskDefinition::GetConfiguration() const +TConfig& TTaskDefinition::GetConfiguration() { - return m_tOperationConfiguration; + return m_tConfiguration; } + +const TConfig& TTaskDefinition::GetConfiguration() const +{ + return m_tConfiguration; +} + +// Serialization +void TTaskDefinition::Load(const CString& strPath) +{ + // read everything + TConfig tTaskInfo; + tTaskInfo.Read(strPath); + + // clear everything + m_strTaskUniqueID.Empty(); + m_vSourcePaths.clear(); + m_strDestinationPath.Empty(); + + m_tConfiguration.Clear(); + + m_bModified = false; + + // get information from config file + // task unique id - use if provided, generate otherwise + tTaskInfo.GetValue(_T("TaskDefinition.UniqueID"), m_strTaskUniqueID, _T("")); + if(m_strTaskUniqueID.IsEmpty()) + { + boost::uuids::random_generator gen; + boost::uuids::uuid u = gen(); + m_strTaskUniqueID = boost::lexical_cast(u).c_str(); + + m_bModified = true; + } + + // basic information + tTaskInfo.GetValue(_T("TaskDefinition.SourcePaths"), m_vSourcePaths); + tTaskInfo.GetValue(_T("TaskDefinition.DestinationPath"), m_strDestinationPath, _T("")); + if(m_strDestinationPath.Right(1) != _T("\\")) + m_strDestinationPath += _T("\\"); + + int iOperation = eOperation_None; + tTaskInfo.GetValue(_T("TaskDefinition.OperationType"), iOperation, eOperation_None); + m_tOperationPlan.SetOperationType((EOperationType)iOperation); + + tTaskInfo.ExtractSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration); +} + +void TTaskDefinition::Store(const CString& strPath, bool bOnlyIfModified) +{ + if(!bOnlyIfModified || m_bModified || m_tConfiguration.IsModified()) + { + // read everything + TConfig tTaskInfo; + tTaskInfo.SetFilePath(strPath); + + // get information from config file + // task unique id - use if provided, generate otherwise + tTaskInfo.SetValue(_T("TaskDefinition.UniqueID"), m_strTaskUniqueID); + + // basic information + tTaskInfo.SetValue(_T("TaskDefinition.SourcePaths.Path"), m_vSourcePaths); + tTaskInfo.SetValue(_T("TaskDefinition.DestinationPath"), m_strDestinationPath); + + int iOperation = m_tOperationPlan.GetOperationType(); + tTaskInfo.SetValue(_T("TaskDefinition.OperationType"), iOperation); + + tTaskInfo.PutSubConfig(_T("TaskDefinition.TaskSettings"), m_tConfiguration); + + tTaskInfo.Write(); + + m_bModified = false; + } +} Index: src/ch/TTaskDefinition.h =================================================================== diff -u -N -rca1933ef07e18d939449e4878eca5cc81cc73f3f -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/TTaskDefinition.h (.../TTaskDefinition.h) (revision ca1933ef07e18d939449e4878eca5cc81cc73f3f) +++ src/ch/TTaskDefinition.h (.../TTaskDefinition.h) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -24,7 +24,8 @@ #define __TTASKDEFINITION_H__ #include "TTaskOperationPlan.h" -#include "TTaskConfiguration.h" +#include "TConfig.h" +#include "FileInfo.h" /////////////////////////////////////////////////////////////////////////// // TTaskDefinition @@ -33,80 +34,54 @@ { public: TTaskDefinition(); + TTaskDefinition(const TTaskDefinition& rSrc); ~TTaskDefinition(); - // initialize object with data (get/set, from cfg file?, from string(cmd line options)) + TTaskDefinition& operator=(const TTaskDefinition& rSrc); + + // Task unique ID + CString GetTaskUniqueID() const; + + // Source paths void AddSourcePath(const CString& strPath); - CString GetSourcePathNameAt(size_t stIndex) const; - CClipboardEntryPtr GetSourcePathAt(size_t stIndex) const; + CString GetSourcePathAt(size_t stIndex) const; size_t GetSourcePathCount() const; + const std::vector& GetSourcePaths() const; + void ClearSourcePaths(); - const CClipboardArray& GetSourcePaths() const; + // Destination path void SetDestinationPath(const CString& strPath); CString GetDestinationPath() const; - const CDestPath& GetDestPath() const; + // Operation type void SetOperationType(EOperationType eOperation); EOperationType GetOperationType() const; const TOperationPlan& GetOperationPlan() const; - TTaskConfiguration& GetConfiguration(); - const TTaskConfiguration& GetConfiguration() const; + // Task configuration + void SetConfig(const TConfig& rConfig); + TConfig& GetConfiguration(); + const TConfig& GetConfiguration() const; - CString GetTaskUniqueID() const; + // Serialization + void Load(const CString& strPath); + void Store(const CString& strPath, bool bOnlyIfModified = false); - // serialize (from/to xml) - template - void Load(Archive& ar, bool bData, const unsigned int uiVersion) - { - if(bData) - { - ar & m_strTaskUniqueID; - m_arrSourcePaths.Load(ar, uiVersion, bData); - ar & m_tDestinationPath; - ar & m_tOperationPlan; - ar & m_tOperationConfiguration; - } - else - { - m_arrSourcePaths.Load(ar, uiVersion, bData); - } - - m_bNeedsSaving = false; - } - - template - void Save(Archive& ar, bool bData, const unsigned int uiVersion) const - { - if(bData) - { - ar & m_strTaskUniqueID; - m_arrSourcePaths.Store(ar, uiVersion, bData); - ar & m_tDestinationPath; - ar & m_tOperationPlan; - ar & m_tOperationConfiguration; - } - else - m_arrSourcePaths.Store(ar, uiVersion, bData); - - m_bNeedsSaving = false; - } - private: - std::wstring m_strTaskUniqueID; ///< Unique ID of the task that will process this request (generated automatically) + CString m_strTaskUniqueID; ///< Unique ID of the task that will process this request (generated automatically) // basic information - CClipboardArray m_arrSourcePaths; ///< Contains source paths to be processed - CDestPath m_tDestinationPath; ///< Contains destination path for the data to be processed to + std::vector m_vSourcePaths; + CString m_strDestinationPath; TOperationPlan m_tOperationPlan; ///< Describes the operation along with sub-operations to be performed on the task input data // Global task settings - TTaskConfiguration m_tOperationConfiguration; + TConfig m_tConfiguration; // Other info (volatile, not to be saved to xml) - mutable bool m_bNeedsSaving; ///< Some parameters has been modified and this object needs to be serialized again + mutable bool m_bModified; ///< Some parameters has been modified and this object needs to be serialized again }; #endif // __TTASKDEFINITION_H__ Index: src/ch/ch.rc =================================================================== diff -u -N -r044d0e17cdedf3055202486a2235e1a3c8dd6e56 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/ch.rc (.../ch.rc) (revision 044d0e17cdedf3055202486a2235e1a3c8dd6e56) +++ src/ch/ch.rc (.../ch.rc) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -221,7 +221,7 @@ CONTROL "",IDC_019_STATIC,"Static",SS_ETCHEDHORZ,249,10,38,1 LTEXT "Time:",IDC_020_STATIC,249,121,62,8 PUSHBUTTON "&Resume",IDC_RESUME_BUTTON,52,196,44,14,0,0,HIDC_RESUME_BUTTON - LTEXT "Associated file:",IDC_021_STATIC,249,19,62,8 + LTEXT "Task ID:",IDC_021_STATIC,249,19,62,8 CONTROL "",IDC_ASSOCIATEDFILES__STATIC,"STATICEX",0x4,313,17,159,12,WS_EX_STATICEDGE,HIDC_ASSOCIATEDFILES__STATIC CONTROL "",IDC_OPERATION_STATIC,"STATICEX",0x4,313,32,159,12,WS_EX_STATICEDGE,HIDC_OPERATION_STATIC CONTROL "",IDC_SOURCE_STATIC,"STATICEX",0x4,313,45,159,12,WS_EX_STATICEDGE,HIDC_SOURCE_STATIC Index: src/ch/ch.vc90.vcproj =================================================================== diff -u -N -r3c3018d15591811e0b3cb35f43ceb31f4914f47e -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 3c3018d15591811e0b3cb35f43ceb31f4914f47e) +++ src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -1,7 +1,7 @@ - - Index: src/ch/task.cpp =================================================================== diff -u -N -r9ea1e103b5fa4ddfebf8028f121ce16e917eec04 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/task.cpp (.../task.cpp) (revision 9ea1e103b5fa4ddfebf8028f121ce16e917eec04) +++ src/ch/task.cpp (.../task.cpp) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -422,11 +422,12 @@ CTask::CTask(chcore::IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID) : m_log(), m_piFeedbackHandler(piFeedbackHandler), - m_files(m_tTaskDefinition.GetSourcePaths()), + m_files(m_arrSourcePaths), m_nPriority(THREAD_PRIORITY_NORMAL), m_bForce(false), m_bContinue(false), - m_bSaved(false), + m_bRareStateModified(false), + m_bOftenStateModified(false), m_stSessionUniqueID(stSessionUniqueID), m_localStats() { @@ -446,6 +447,23 @@ m_piFeedbackHandler->Delete(); } +void CTask::SetTaskDefinition(const TTaskDefinition& rTaskDefinition) +{ + m_tTaskDefinition = rTaskDefinition; + + m_arrSourcePaths.RemoveAll(); + m_files.Clear(); + + BOOST_FOREACH(const CString& strPath, m_tTaskDefinition.GetSourcePaths()) + { + CClipboardEntryPtr spEntry(new CClipboardEntry); + spEntry->SetPath(strPath); + + m_arrSourcePaths.Add(spEntry); + } + m_tDestinationPath.SetPath(m_tTaskDefinition.GetDestinationPath()); +} + void CTask::OnRegisterTask(TTasksGlobalStats& rtGlobalStats) { m_localStats.ConnectGlobalStats(rtGlobalStats); @@ -477,7 +495,7 @@ if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { CFileInfoPtr spFileInfo(boost::make_shared()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) + spFileInfo->SetClipboard(&m_arrSourcePaths); // this is the link table (CClipboardArray) spFileInfo->Create(&wfd, strDirName, stSrcIndex); if(m_afFilters.Match(spFileInfo)) @@ -488,7 +506,7 @@ if(bIncludeDirs) { CFileInfoPtr spFileInfo(boost::make_shared()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); // this is the link table (CClipboardArray) + spFileInfo->SetClipboard(&m_arrSourcePaths); // this is the link table (CClipboardArray) // Add directory itself spFileInfo->Create(&wfd, strDirName, stSrcIndex); @@ -530,8 +548,8 @@ void CTask::SetBufferSizes(const BUFFERSIZES* bsSizes) { boost::unique_lock lock(m_lock); - m_bsSizes=*bsSizes; - m_bSaved=false; + m_bsSizes = *bsSizes; + m_bOftenStateModified = true; } const BUFFERSIZES* CTask::GetBufferSizes() @@ -542,7 +560,7 @@ int CTask::GetCurrentBufferIndex() { - return m_files.GetBufferIndexAt(m_TTaskBasicProgressInfo.GetCurrentIndex(), m_tTaskDefinition.GetDestPath()); + return m_files.GetBufferIndexAt(m_tTaskBasicProgressInfo.GetCurrentIndex(), m_tDestinationPath); } // m_pThread @@ -582,94 +600,104 @@ void CTask::CalculateProcessedSizeNL() { - m_localStats.SetProcessedSize(m_files.CalculatePartialSize(m_TTaskBasicProgressInfo.GetCurrentIndex())); + m_localStats.SetProcessedSize(m_files.CalculatePartialSize(m_tTaskBasicProgressInfo.GetCurrentIndex())); } -void CTask::Load(const CString& strPath, bool bData) +void CTask::Load(const CString& strPath) { - std::ifstream ifs(strPath, ios_base::in | ios_base::binary); - boost::archive::binary_iarchive ar(ifs); - boost::unique_lock lock(m_lock); - if(bData) - { - m_tTaskDefinition.Load(ar, bData, 0); - m_files.Load(ar, 0, false); + //////////////////////////////// + // First load task description + m_tTaskDefinition.Load(strPath); + m_strFilePath = strPath; - CalculateTotalSizeNL(); + //////////////////////////////// + // now rarely changing task progress data + CString strRarelyChangingPath = GetRelatedPathNL(ePathType_TaskRarelyChangingState); + std::ifstream ifs(strRarelyChangingPath, ios_base::in | ios_base::binary); + boost::archive::binary_iarchive ar(ifs); - ar >> m_afFilters; - } - else - { - m_tTaskDefinition.Load(ar, bData, 0); + m_arrSourcePaths.Load(ar, 0, true); + m_files.Load(ar, 0, false); - ar >> m_TTaskBasicProgressInfo; + CalculateTotalSizeNL(); - CalculateProcessedSizeNL(); + ar >> m_afFilters; - // load task state, convert "waiting" state to "processing" - int iState = eTaskState_None; - ar >> iState; - if(iState >= eTaskState_None && iState < eTaskState_Max) - { - if(iState == eTaskState_Waiting) - iState = eTaskState_Processing; - m_eCurrentState = (ETaskCurrentState)iState; - } - else - { - BOOST_ASSERT(false); - THROW(_T("Wrong data read from stream"), 0, 0, 0); - } + /////////////////////////////////// + // and often changing data + CString strOftenChangingPath = GetRelatedPathNL(ePathType_TaskOftenChangingState); + std::ifstream ifs2(strOftenChangingPath, ios_base::in | ios_base::binary); + boost::archive::binary_iarchive ar2(ifs2); - ar >> m_bsSizes; - ar >> m_nPriority; + ar2 >> m_tTaskBasicProgressInfo; - time_t timeElapsed = 0; - ar >> timeElapsed; - m_localStats.SetTimeElapsed(timeElapsed); + CalculateProcessedSizeNL(); - m_files.Load(ar, 0, true); - - ar >> m_bSaved; + // load task state, convert "waiting" state to "processing" + int iState = eTaskState_None; + ar2 >> iState; + if(iState >= eTaskState_None && iState < eTaskState_Max) + { + if(iState == eTaskState_Waiting) + iState = eTaskState_Processing; + m_eCurrentState = (ETaskCurrentState)iState; } + else + { + BOOST_ASSERT(false); + THROW(_T("Wrong data read from stream"), 0, 0, 0); + } + + ar2 >> m_bsSizes; + ar2 >> m_nPriority; + + time_t timeElapsed = 0; + ar2 >> timeElapsed; + m_localStats.SetTimeElapsed(timeElapsed); + + m_arrSourcePaths.Load(ar2, 0, false); + m_files.Load(ar2, 0, true); } -void CTask::Store(bool bData) +void CTask::Store() { - boost::shared_lock lock(m_lock); - BOOST_ASSERT(!m_strTaskBasePath.empty()); - if(m_strTaskBasePath.empty()) + boost::upgrade_lock lock(m_lock); + + BOOST_ASSERT(!m_strTaskDirectory.IsEmpty()); + if(m_strTaskDirectory.IsEmpty()) THROW(_t("Missing task path."), 0, 0, 0); - if(!bData && m_bSaved) - return; - - if(!bData && !m_bSaved && (m_eCurrentState == eTaskState_Finished || m_eCurrentState == eTaskState_Cancelled || m_eCurrentState == eTaskState_Paused)) + // generate file path if not available yet + if(m_strFilePath.IsEmpty()) { - m_bSaved = true; + boost::upgrade_to_unique_lock upgraded_lock(lock); + m_strFilePath = m_strTaskDirectory + m_tTaskDefinition.GetTaskUniqueID() + _T(".cht"); } - CString strPath = m_strTaskBasePath.c_str() + m_tTaskDefinition.GetTaskUniqueID() + (bData ? _T(".atd") : _T(".atp")); + // store task definition only if changed + m_tTaskDefinition.Store(GetRelatedPathNL(ePathType_TaskDefinition), true); - std::ofstream ofs(strPath, ios_base::out | ios_base::binary); - boost::archive::binary_oarchive ar(ofs); - - if(bData) + // rarely changing data + if(m_bRareStateModified) { - m_tTaskDefinition.Save(ar, bData, 0); + std::ofstream ofs(GetRelatedPathNL(ePathType_TaskRarelyChangingState), ios_base::out | ios_base::binary); + boost::archive::binary_oarchive ar(ofs); + m_arrSourcePaths.Store(ar, 0, true); m_files.Store(ar, 0, false); ar << m_afFilters; } - else + + if(m_bOftenStateModified) { - m_tTaskDefinition.Save(ar, bData, 0); - ar << m_TTaskBasicProgressInfo; + std::ofstream ofs(GetRelatedPathNL(ePathType_TaskOftenChangingState), ios_base::out | ios_base::binary); + boost::archive::binary_oarchive ar(ofs); + ar << m_tTaskBasicProgressInfo; + // store current state (convert from waiting to processing state before storing) int iState = m_eCurrentState; if(iState == eTaskState_Waiting) @@ -683,15 +711,16 @@ time_t timeElapsed = m_localStats.GetTimeElapsed(); ar << timeElapsed; - ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_TTaskBasicProgressInfo.GetSubOperationIndex()); + m_arrSourcePaths.Store(ar, 0, false); + + ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex()); if(eSubOperation != eSubOperation_Scanning) m_files.Store(ar, 0, true); else { size_t st(0); ar << st; } - ar << m_bSaved; } } @@ -704,7 +733,8 @@ { boost::unique_lock lock(m_lock); - m_bSaved = false; // save + m_bRareStateModified = true; + m_bOftenStateModified = true; m_workerThread.StartThread(DelegateThreadProc, this, m_nPriority); } @@ -737,7 +767,7 @@ SetTaskState(eTaskState_None); m_localStats.SetTimeElapsed(0); - m_TTaskBasicProgressInfo.SetCurrentIndex(0); + m_tTaskBasicProgressInfo.SetCurrentIndex(0); BeginProcessing(); } @@ -748,7 +778,8 @@ { KillThread(); SetTaskState(eTaskState_Paused); - m_bSaved = false; + + m_bOftenStateModified = true; } } @@ -759,14 +790,14 @@ { KillThread(); SetTaskState(eTaskState_Cancelled); - m_bSaved=false; + m_bOftenStateModified = true; } } void CTask::GetMiniSnapshot(TASK_MINI_DISPLAY_DATA *pData) { boost::shared_lock lock(m_lock); - size_t stCurrentIndex = m_TTaskBasicProgressInfo.GetCurrentIndex(); + size_t stCurrentIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); if(stCurrentIndex < m_files.GetSize()) pData->m_strPath = m_files.GetAt(stCurrentIndex)->GetFileName(); @@ -777,7 +808,7 @@ else { if(m_tTaskDefinition.GetSourcePathCount() > 0) - pData->m_strPath = m_tTaskDefinition.GetSourcePathAt(0)->GetFileName(); + pData->m_strPath = m_arrSourcePaths.GetAt(0)->GetFileName(); else pData->m_strPath = GetResManager().LoadString(IDS_NONEINPUTFILE_STRING); } @@ -793,7 +824,7 @@ { boost::unique_lock lock(m_lock); - size_t stCurrentIndex = m_TTaskBasicProgressInfo.GetCurrentIndex(); + size_t stCurrentIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); if(stCurrentIndex < m_files.GetSize()) { pData->m_strFullFilePath = m_files.GetAt(stCurrentIndex)->GetFullFilePath(); @@ -810,8 +841,8 @@ { if(m_tTaskDefinition.GetSourcePathCount() > 0) { - pData->m_strFullFilePath = m_tTaskDefinition.GetSourcePathAt(0)->GetPath(); - pData->m_strFileName = m_tTaskDefinition.GetSourcePathAt(0)->GetFileName(); + pData->m_strFullFilePath = m_arrSourcePaths.GetAt(0)->GetPath(); + pData->m_strFileName = m_arrSourcePaths.GetAt(0)->GetFileName(); } else { @@ -833,7 +864,7 @@ pData->m_strUniqueName = m_tTaskDefinition.GetTaskUniqueID(); if(m_files.GetSize() > 0) - pData->m_iCurrentBufferIndex=m_bsSizes.m_bOnlyDefault ? 0 : m_files.GetAt((stCurrentIndex < m_files.GetSize()) ? stCurrentIndex : 0)->GetBufferIndex(m_tTaskDefinition.GetDestPath()); + pData->m_iCurrentBufferIndex=m_bsSizes.m_bOnlyDefault ? 0 : m_files.GetAt((stCurrentIndex < m_files.GetSize()) ? stCurrentIndex : 0)->GetBufferIndex(m_tDestinationPath); else pData->m_iCurrentBufferIndex=0; @@ -880,7 +911,7 @@ // second part EOperationType eOperationType = m_tTaskDefinition.GetOperationType(); - ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_TTaskBasicProgressInfo.GetSubOperationIndex()); + ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex()); if(eSubOperation == eSubOperation_Deleting) _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+6)); else if(eSubOperation == eSubOperation_Scanning) @@ -901,12 +932,12 @@ _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+7)); // third part - if(m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetIgnoreDirectories()) + if(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) { _tcscat(pData->m_szStatusText, _T("/")); _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+10)); } - if(m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetCreateEmptyFiles()) + if(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())) { _tcscat(pData->m_szStatusText, _T("/")); _tcscat(pData->m_szStatusText, GetResManager().LoadString(IDS_STATUS0_STRING+11)); @@ -916,19 +947,24 @@ pData->m_timeElapsed = m_localStats.GetTimeElapsed(); } -void CTask::DeleteProgress(LPCTSTR lpszDirectory) +void CTask::DeleteProgress() { - m_lock.lock_shared(); + std::vector vFilesToRemove; - CString strDel1 = lpszDirectory + m_tTaskDefinition.GetTaskUniqueID() + _T(".atd"); - CString strDel2 = lpszDirectory + m_tTaskDefinition.GetTaskUniqueID() + _T(".atp"); - CString strDel3 = lpszDirectory + m_tTaskDefinition.GetTaskUniqueID() + _T(".log"); + // separate scope for shared locking + { + boost::shared_lock lock(m_lock); - m_lock.unlock_shared(); + vFilesToRemove.push_back(GetRelatedPath(ePathType_TaskDefinition)); + vFilesToRemove.push_back(GetRelatedPath(ePathType_TaskRarelyChangingState)); + vFilesToRemove.push_back(GetRelatedPath(ePathType_TaskOftenChangingState)); + vFilesToRemove.push_back(GetRelatedPath(ePathType_TaskLogFile)); + } - DeleteFile(strDel1); - DeleteFile(strDel2); - DeleteFile(strDel3); + BOOST_FOREACH(const CString& strFile, vFilesToRemove) + { + DeleteFile(strFile); + } } void CTask::SetFilters(const CFiltersArray* pFilters) @@ -974,18 +1010,30 @@ return (*pullNeeded <= *pullAvailable); } -void CTask::SetTaskPath(const tchar_t* pszDir) +void CTask::SetTaskDirectory(const CString& strDir) { boost::unique_lock lock(m_lock); - m_strTaskBasePath = pszDir; + m_strTaskDirectory = strDir; } -const tchar_t* CTask::GetTaskPath() const +CString CTask::GetTaskDirectory() const { boost::shared_lock lock(m_lock); - return m_strTaskBasePath.c_str(); + return m_strTaskDirectory; } +void CTask::SetTaskFilePath(const CString& strFilePath) +{ + boost::unique_lock lock(m_lock); + m_strFilePath = strFilePath; +} + +CString CTask::GetTaskFilePath() const +{ + boost::shared_lock lock(m_lock); + return m_strFilePath; +} + void CTask::SetForceFlag(bool bFlag) { boost::unique_lock lock(m_lock); @@ -1029,7 +1077,7 @@ void CTask::SetBufferSizesNL(const BUFFERSIZES* bsSizes) { m_bsSizes = *bsSizes; - m_bSaved = false; + m_bOftenStateModified = true; } const BUFFERSIZES* CTask::GetBufferSizesNL() @@ -1049,7 +1097,7 @@ m_workerThread.ChangePriority(nPriority); m_nPriority = nPriority; - m_bSaved = false; + m_bOftenStateModified = true; } void CTask::CalculateTotalSizeNL() @@ -1095,9 +1143,9 @@ m_files.Clear(); // enter some data to m_files - int iDestDrvNumber = m_tTaskDefinition.GetDestPath().GetDriveNumber(); - bool bIgnoreDirs = m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetIgnoreDirectories(); - bool bForceDirectories = m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetCreateOnlyDirectories(); + int iDestDrvNumber = m_tDestinationPath.GetDriveNumber(); + bool bIgnoreDirs = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + bool bForceDirectories = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); bool bMove = m_tTaskDefinition.GetOperationType() == eOperation_Move; // add everything @@ -1113,18 +1161,18 @@ bSkipInputPath = false; spFileInfo.reset(new CFileInfo()); - spFileInfo->SetClipboard(&m_tTaskDefinition.GetSourcePaths()); + spFileInfo->SetClipboard(&m_arrSourcePaths); // try to get some info about the input path; let user know if the path does not exist. do { bRetry = false; // read attributes of src file/folder - bool bExists = spFileInfo->Create(m_tTaskDefinition.GetSourcePathNameAt(stIndex), stIndex); + bool bExists = spFileInfo->Create(m_arrSourcePaths.GetAt(stIndex)->GetPath(), stIndex); if(!bExists) { - CString strSrcFile = m_tTaskDefinition.GetSourcePathNameAt(stIndex); + CString strSrcFile = m_arrSourcePaths.GetAt(stIndex)->GetPath(); FEEDBACK_FILEERROR ferr = { (PCTSTR)strSrcFile, NULL, eFastMoveError, ERROR_FILE_NOT_FOUND }; CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_FileError, &ferr); switch(frResult) @@ -1159,21 +1207,21 @@ // log fmt.SetFormat(_T("Adding file/folder (clipboard) : %path ...")); - fmt.SetParam(_t("%path"), m_tTaskDefinition.GetSourcePathNameAt(stIndex)); + fmt.SetParam(_t("%path"), m_arrSourcePaths.GetAt(stIndex)->GetPath()); m_log.logi(fmt); // found file/folder - check if the dest name has been generated - if(!m_tTaskDefinition.GetSourcePathAt(stIndex)->IsDestinationPathSet()) + if(!m_arrSourcePaths.GetAt(stIndex)->IsDestinationPathSet()) { // generate something - if dest folder == src folder - search for copy if(m_tTaskDefinition.GetDestinationPath() == spFileInfo->GetFileRoot()) { CString strSubst; FindFreeSubstituteName(spFileInfo->GetFullFilePath(), m_tTaskDefinition.GetDestinationPath(), &strSubst); - m_tTaskDefinition.GetSourcePathAt(stIndex)->SetDestinationPath(strSubst); + m_arrSourcePaths.GetAt(stIndex)->SetDestinationPath(strSubst); } else - m_tTaskDefinition.GetSourcePathAt(stIndex)->SetDestinationPath(spFileInfo->GetFileName()); + m_arrSourcePaths.GetAt(stIndex)->SetDestinationPath(spFileInfo->GetFileName()); } // add if needed @@ -1201,7 +1249,7 @@ m_log.logi(fmt); // no movefile possibility - use CustomCopyFileFB - m_tTaskDefinition.GetSourcePathAt(stIndex)->SetMove(false); + m_arrSourcePaths.GetAt(stIndex)->SetMove(false); ScanDirectory(spFileInfo->GetFullFilePath(), stIndex, true, !bIgnoreDirs || bForceDirectories); } @@ -1225,7 +1273,7 @@ spFileInfo->SetLength64(0); } else - m_tTaskDefinition.GetSourcePathAt(stIndex)->SetMove(false); // no MoveFile + m_arrSourcePaths.GetAt(stIndex)->SetMove(false); // no MoveFile // add file info if passes filters if(m_afFilters.Match(spFileInfo)) @@ -1242,8 +1290,7 @@ CalculateTotalSize(); // save task status - Store(true); - Store(false); + Store(); // log m_log.logi(_T("Searching for files finished")); @@ -1263,11 +1310,11 @@ ictranslate::CFormat fmt; // index points to 0 or next item to process - size_t stIndex = m_TTaskBasicProgressInfo.GetCurrentIndex(); + size_t stIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); while(stIndex < m_files.GetSize()) { // set index in pTask to currently deleted element - m_TTaskBasicProgressInfo.SetCurrentIndex(stIndex); + m_tTaskBasicProgressInfo.SetCurrentIndex(stIndex); // check for kill flag if(m_workerThread.KillRequested()) @@ -1341,7 +1388,7 @@ SetTaskState(eTaskState_Finished); // add 1 to current index - m_TTaskBasicProgressInfo.IncreaseCurrentIndex(); + m_tTaskBasicProgressInfo.IncreaseCurrentIndex(); // log m_log.logi(_T("Deleting files finished")); @@ -1822,7 +1869,7 @@ else if(hSrc == INVALID_HANDLE_VALUE) { // invalid handle = operation skipped by user - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } @@ -1837,7 +1884,7 @@ unsigned long long ullSeekTo = 0; bool bDstFileFreshlyCreated = false; - if(m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize() == 0) + if(m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize() == 0) { // open destination file for case, when we start operation on this file (i.e. it is not resume of the // old operation) @@ -1846,7 +1893,7 @@ return eResult; else if(hDst == INVALID_HANDLE_VALUE) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } @@ -1859,12 +1906,12 @@ return eResult; else if(hDst == INVALID_HANDLE_VALUE) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } - ullSeekTo = m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize(); + ullSeekTo = m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize(); } if(!pData->bOnlyCreate) @@ -1880,7 +1927,7 @@ return eResult; else if(bSkip) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } @@ -1891,12 +1938,12 @@ else if(bSkip) { // with either first or second seek we got 'skip' answer... - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } - m_TTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ullMove); + m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ullMove); m_localStats.IncreaseProcessedSize(ullMove); } @@ -1964,7 +2011,7 @@ if(GetBufferSizes()->m_bOnlyDefault) iBufferIndex = BI_DEFAULT; else - iBufferIndex = pData->spSrcFile->GetBufferIndex(m_tTaskDefinition.GetDestPath()); + iBufferIndex = pData->spSrcFile->GetBufferIndex(m_tDestinationPath); ulToRead = bNoBuffer ? ROUNDUP(pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex], MAXSECTORSIZE) : pData->dbBuffer.GetSizes()->m_auiSizes[iBufferIndex]; @@ -1974,7 +2021,7 @@ return eResult; else if(bSkip) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } @@ -2000,13 +2047,13 @@ return eResult; else if(bSkip) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } // increase count of processed data - m_TTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulWritten); + m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulWritten); m_localStats.IncreaseProcessedSize(ulWritten); // calculate count of bytes left to be written @@ -2028,19 +2075,19 @@ return eResult; else if(hDst == INVALID_HANDLE_VALUE) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } // move file pointer to the end of destination file - eResult = SetFilePointerFB(hDst, m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize(), pData->strDstFile, bSkip); + eResult = SetFilePointerFB(hDst, m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize(), pData->strDstFile, bSkip); if(eResult != eSubResult_Continue) return eResult; else if(bSkip) { // with either first or second seek we got 'skip' answer... - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } @@ -2055,13 +2102,13 @@ return eResult; else if(bSkip) { - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); pData->bProcessed = false; return eSubResult_Continue; } // increase count of processed data - m_TTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulRead); + m_tTaskBasicProgressInfo.IncreaseCurrentFileProcessedSize(ulRead); m_localStats.IncreaseProcessedSize(ulRead); } } @@ -2071,11 +2118,11 @@ else { // we don't copy contents, but need to increase processed size - m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_TTaskBasicProgressInfo.GetCurrentFileProcessedSize()); + m_localStats.IncreaseProcessedSize(pData->spSrcFile->GetLength64() - m_tTaskBasicProgressInfo.GetCurrentFileProcessedSize()); } pData->bProcessed = true; - m_TTaskBasicProgressInfo.SetCurrentFileProcessedSize(0); + m_tTaskBasicProgressInfo.SetCurrentFileProcessedSize(0); return eSubResult_Continue; } @@ -2091,16 +2138,15 @@ // begin at index which wasn't processed previously size_t stSize = m_files.GetSize(); - bool bIgnoreFolders = m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetIgnoreDirectories(); - bool bForceDirectories = m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetCreateOnlyDirectories(); - const CDestPath& dpDestPath = m_tTaskDefinition.GetDestPath(); + bool bIgnoreFolders = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + bool bForceDirectories = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); // create a buffer of size m_nBufferSize CUSTOM_COPY_PARAMS ccp; ccp.bProcessed = false; - ccp.bOnlyCreate = m_tTaskDefinition.GetConfiguration().GetCopyMoveConfig().GetCreateEmptyFiles(); + ccp.bOnlyCreate = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); ccp.dbBuffer.Create(GetBufferSizes()); - ccp.pDestPath = &dpDestPath; + ccp.pDestPath = &m_tDestinationPath; // helpers DWORD dwLastError = 0; @@ -2118,12 +2164,12 @@ fmt.SetParam(_t("%lansize"), pbs->m_uiLANSize); fmt.SetParam(_t("%filecount"), stSize); fmt.SetParam(_t("%ignorefolders"), bIgnoreFolders); - fmt.SetParam(_t("%dstpath"), dpDestPath.GetPath()); - fmt.SetParam(_t("%currindex"), m_TTaskBasicProgressInfo.GetCurrentIndex()); + fmt.SetParam(_t("%dstpath"), m_tDestinationPath.GetPath()); + fmt.SetParam(_t("%currindex"), m_tTaskBasicProgressInfo.GetCurrentIndex()); m_log.logi(fmt); - for(size_t stIndex = m_TTaskBasicProgressInfo.GetCurrentIndex(); stIndex < stSize; stIndex++) + for(size_t stIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); stIndex < stSize; stIndex++) { // should we kill ? if(m_workerThread.KillRequested()) @@ -2134,14 +2180,14 @@ } // update m_stNextIndex, getting current CFileInfo - CFileInfoPtr spFileInfo = m_files.GetAt(m_TTaskBasicProgressInfo.GetCurrentIndex()); + CFileInfoPtr spFileInfo = m_files.GetAt(m_tTaskBasicProgressInfo.GetCurrentIndex()); // set dest path with filename - ccp.strDstFile = spFileInfo->GetDestinationPath(dpDestPath.GetPath(), ((int)bForceDirectories) << 1 | (int)bIgnoreFolders); + ccp.strDstFile = spFileInfo->GetDestinationPath(m_tDestinationPath.GetPath(), ((int)bForceDirectories) << 1 | (int)bIgnoreFolders); // are the files/folders lie on the same partition ? bool bMove = m_tTaskDefinition.GetOperationType() == eOperation_Move; - if(bMove && dpDestPath.GetDriveNumber() != -1 && dpDestPath.GetDriveNumber() == spFileInfo->GetDriveNumber() && spFileInfo->GetMove()) + if(bMove && m_tDestinationPath.GetDriveNumber() != -1 && m_tDestinationPath.GetDriveNumber() == spFileInfo->GetDriveNumber() && spFileInfo->GetMove()) { bool bRetry = true; if(bRetry && !MoveFile(spFileInfo->GetFullFilePath(), ccp.strDstFile)) @@ -2252,14 +2298,14 @@ SetFileAttributes(ccp.strDstFile, spFileInfo->GetAttributes()); // as above } - m_TTaskBasicProgressInfo.SetCurrentIndex(stIndex + 1); + m_tTaskBasicProgressInfo.SetCurrentIndex(stIndex + 1); } // delete buffer - it's not needed ccp.dbBuffer.Delete(); // to look better (as 100%) - increase current index by 1 - m_TTaskBasicProgressInfo.SetCurrentIndex(stSize); + m_tTaskBasicProgressInfo.SetCurrentIndex(stSize); // log m_log.logi(_T("Finished processing in ProcessFiles")); @@ -2318,7 +2364,7 @@ if(m_tTaskDefinition.GetSourcePathCount() > 0) { - CString strSrcPath = m_tTaskDefinition.GetSourcePathAt(0)->GetPath(); + CString strSrcPath = m_arrSourcePaths.GetAt(0)->GetPath(); CString strDstPath = m_tTaskDefinition.GetDestinationPath(); FEEDBACK_NOTENOUGHSPACE feedStruct = { ullNeededSize, (PCTSTR)strSrcPath, (PCTSTR)strDstPath }; CFeedbackHandler::EFeedbackResult frResult = (CFeedbackHandler::EFeedbackResult)m_piFeedbackHandler->RequestFeedback(CFeedbackHandler::eFT_NotEnoughSpace, &feedStruct); @@ -2368,10 +2414,9 @@ CTask::ESubOperationResult eResult = eSubResult_Continue; // initialize log file - tstring_t strPath = GetTaskPath(); - strPath += m_tTaskDefinition.GetTaskUniqueID() + _T(".log"); + CString strPath = GetRelatedPath(ePathType_TaskLogFile); - m_log.init(strPath.c_str(), 262144, icpf::log_file::level_debug, false, false); + m_log.init(strPath, 262144, icpf::log_file::level_debug, false, false); // start operation OnBeginOperation(); @@ -2384,7 +2429,7 @@ bool bReadTasksSize = GetPropValue(GetConfig()); // wait for permission to really start (but only if search for files is not allowed to start regardless of the lock) - size_t stSubOperationIndex = m_TTaskBasicProgressInfo.GetSubOperationIndex(); + size_t stSubOperationIndex = m_tTaskBasicProgressInfo.GetSubOperationIndex(); if(!bReadTasksSize || stSubOperationIndex != 0 || m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() == 0 || m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(0) != eSubOperation_Scanning) eResult = CheckForWaitState(); // operation limiting @@ -2394,7 +2439,7 @@ for(; stSubOperationIndex < m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() && eResult == eSubResult_Continue; ++stSubOperationIndex) { // set current sub-operation index to allow resuming - m_TTaskBasicProgressInfo.SetSubOperationIndex(stSubOperationIndex); + m_tTaskBasicProgressInfo.SetSubOperationIndex(stSubOperationIndex); ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(stSubOperationIndex); switch(eSubOperation) @@ -2474,16 +2519,17 @@ } // perform cleanup dependent on currently executing subtask - switch(m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_TTaskBasicProgressInfo.GetSubOperationIndex())) + switch(m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex())) { case eSubOperation_Scanning: m_files.Clear(); // get rid of m_files contents - Store(true); // save state of a task + m_bRareStateModified = true; break; } // save progress before killed - Store(false); + m_bOftenStateModified = true; + Store(); // reset flags SetContinueFlag(false); @@ -2557,6 +2603,43 @@ m_workerThread.SignalThreadToStop(); } +CString CTask::GetRelatedPath(EPathType ePathType) +{ + boost::shared_lock lock(m_lock); + + return GetRelatedPathNL(ePathType); +} + +CString CTask::GetRelatedPathNL(EPathType ePathType) +{ + BOOST_ASSERT(!m_strTaskDirectory.IsEmpty() || !m_strFilePath.IsEmpty()); + if(m_strTaskDirectory.IsEmpty() && m_strFilePath.IsEmpty()) + THROW(_t("Missing task path."), 0, 0, 0); + + // in all cases we would like to have task definition path defined + CString strFilePath = m_strFilePath; + if(strFilePath.IsEmpty()) + strFilePath = m_strTaskDirectory + m_tTaskDefinition.GetTaskUniqueID() + _T(".cht"); + + switch(ePathType) + { + case ePathType_TaskDefinition: + return strFilePath; + + case ePathType_TaskRarelyChangingState: + return strFilePath + _T(".rstate"); + + case ePathType_TaskOftenChangingState: + return strFilePath + _T(".ostate"); + + case ePathType_TaskLogFile: + return strFilePath + _T(".log"); + + default: + THROW(_t("Unhandled case"), 0, 0, 0); + } +} + //////////////////////////////////////////////////////////////////////////////// // CTaskArray members CTaskArray::CTaskArray() : @@ -2641,7 +2724,7 @@ boost::unique_lock lock(m_lock); // here we know load succeeded - spNewTask->SetTaskPath(m_strTasksDir.c_str()); + spNewTask->SetTaskDirectory(m_strTasksDir.c_str()); m_vTasks.push_back(spNewTask); @@ -2707,7 +2790,7 @@ BOOST_FOREACH(CTaskPtr& spTask, vTasksToRemove) { // delete associated files - spTask->DeleteProgress(m_strTasksDir.c_str()); + spTask->DeleteProgress(); } } @@ -2728,7 +2811,7 @@ spTask->OnUnregisterTask(); // delete associated files - spTask->DeleteProgress(m_strTasksDir.c_str()); + spTask->DeleteProgress(); m_vTasks.erase(iterTask); @@ -2767,26 +2850,18 @@ boost::shared_lock lock(m_lock); BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) { - spTask->Store(true); + spTask->Store(); } } -void CTaskArray::SaveProgress() -{ - boost::shared_lock lock(m_lock); - BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) - { - spTask->Store(false); - } -} - void CTaskArray::LoadDataProgress() { CFileFind finder; CTaskPtr spTask; CString strPath; - - BOOL bWorking=finder.FindFile(CString(m_strTasksDir.c_str())+_T("*.atd")); + + // find all CH Task files + BOOL bWorking = finder.FindFile(CString(m_strTasksDir.c_str()) + _T("*.cht")); while(bWorking) { bWorking = finder.FindNextFile(); @@ -2795,15 +2870,8 @@ spTask = CreateTask(); try { - strPath = finder.GetFilePath(); + spTask->Load(finder.GetFilePath()); - spTask->Load(strPath, true); - - strPath = strPath.Left(strPath.GetLength() - 4); - strPath += _T(".atp"); - - spTask->Load(strPath, false); - // add read task to array Add(spTask); } Index: src/ch/task.h =================================================================== diff -u -N -r0660fea6e85becc94c8ac5c9ce41ba270726efd2 -r1d7d79169d480a02e335b8b0a4919f9c78d58325 --- src/ch/task.h (.../task.h) (revision 0660fea6e85becc94c8ac5c9ce41ba270726efd2) +++ src/ch/task.h (.../task.h) (revision 1d7d79169d480a02e335b8b0a4919f9c78d58325) @@ -260,10 +260,19 @@ }; public: + enum EPathType + { + ePathType_TaskDefinition, + ePathType_TaskRarelyChangingState, + ePathType_TaskOftenChangingState, + ePathType_TaskLogFile, + }; + +public: CTask(chcore::IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID); ~CTask(); - void SetTaskDefinition(const TTaskDefinition& rTaskDefinition) { m_tTaskDefinition = rTaskDefinition; } + void SetTaskDefinition(const TTaskDefinition& rTaskDefinition); const TTaskDefinition& GetTaskDefinition() const { return m_tTaskDefinition; } void SetFilters(const CFiltersArray* pFilters); @@ -281,8 +290,8 @@ int GetPriority(); void SetPriority(int nPriority); - void Load(const CString& strPath, bool bData); - void Store(bool bData); + void Load(const CString& strPath); + void Store(); void BeginProcessing(); @@ -295,14 +304,19 @@ void GetSnapshot(TASK_DISPLAY_DATA *pData); void GetMiniSnapshot(TASK_MINI_DISPLAY_DATA *pData); - void SetTaskPath(const tchar_t* pszDir); - const tchar_t* GetTaskPath() const; + void SetTaskDirectory(const CString& strDir); + CString GetTaskDirectory() const; + void SetTaskFilePath(const CString& strPath); + CString GetTaskFilePath() const; + void SetForceFlag(bool bFlag = true); bool GetForceFlag(); size_t GetSessionUniqueID() const { return m_stSessionUniqueID; } + CString GetRelatedPath(EPathType ePathType); + protected: // methods are called when task is being added or removed from the global task array /// Method is called when this task is being added to a CTaskArray object @@ -368,7 +382,7 @@ void CalculateTotalSize(); void CalculateTotalSizeNL(); - void DeleteProgress(LPCTSTR lpszDirectory); + void DeleteProgress(); void SetForceFlagNL(bool bFlag = true); bool GetForceFlagNL(); @@ -383,10 +397,15 @@ void KillThread(); void RequestStopThread(); + CString GetRelatedPathNL(EPathType ePathType); + private: // task initial information (needed to start a task); might be a bit processed. TTaskDefinition m_tTaskDefinition; + CClipboardArray m_arrSourcePaths; + CDestPath m_tDestinationPath; + // task settings int m_nPriority; // task priority (really processing thread priority) @@ -401,17 +420,20 @@ // changing fast volatile ETaskCurrentState m_eCurrentState; // current state of processing this task represents - TTaskBasicProgressInfo m_TTaskBasicProgressInfo; // task progress information + TTaskBasicProgressInfo m_tTaskBasicProgressInfo; // task progress information // task control variables (per-session state) TTaskLocalStats m_localStats; // local statistics bool m_bForce; // if the continuation of tasks should be independent of max concurrently running task limit bool m_bContinue; // allows task to continue - tstring_t m_strTaskBasePath; // base path at which the files will be stored - bool m_bSaved; // has the state been saved ('til next modification) + CString m_strTaskDirectory; // base path at which the files will be stored + CString m_strFilePath; // exact filename with path to the task definition file + bool m_bRareStateModified; // rarely changing state has been modified + bool m_bOftenStateModified; // rarely changing state has been modified + size_t m_stSessionUniqueID; ///< Per-session unique ID for this task // other helpers @@ -460,7 +482,6 @@ void StopAllTasks(); void SaveData(); - void SaveProgress(); void LoadDataProgress(); void TasksBeginProcessing();