Index: src/ch/ClipboardMonitor.cpp =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/ClipboardMonitor.cpp (.../ClipboardMonitor.cpp) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/ch/ClipboardMonitor.cpp (.../ClipboardMonitor.cpp) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -23,10 +23,9 @@ #include "../libchcore/TWorkerThreadController.h" #include "ClipboardMonitor.h" #include "ch.h" -#include "task.h" +#include "../libchcore/task.h" #include "CfgProperties.h" #include "FolderDialog.h" -#include "task.h" #include "ShutdownDlg.h" CClipboardMonitor CClipboardMonitor::S_ClipboardMonitor; @@ -40,7 +39,7 @@ Stop(); } -void CClipboardMonitor::StartMonitor(CTaskArray* pTasks) +void CClipboardMonitor::StartMonitor(chcore::CTaskArray* pTasks) { CClipboardMonitor::S_ClipboardMonitor.Start(pTasks); } @@ -50,7 +49,7 @@ return CClipboardMonitor::S_ClipboardMonitor.Stop(); } -void CClipboardMonitor::Start(CTaskArray* pTasks) +void CClipboardMonitor::Start(chcore::CTaskArray* pTasks) { m_pTasks = pTasks; @@ -181,7 +180,7 @@ chcore::SetTaskPropValue(tTaskDefinition.GetConfiguration(), GetResManager().LoadString(IDS_FIRSTCOPY_STRING)); chcore::SetTaskPropValue(tTaskDefinition.GetConfiguration(), GetResManager().LoadString(IDS_NEXTCOPY_STRING)); - CTaskPtr spTask = pData->m_pTasks->CreateTask(tTaskDefinition); + chcore::CTaskPtr spTask = pData->m_pTasks->CreateTask(tTaskDefinition); // write spTask to a file spTask->Store(); Index: src/ch/ClipboardMonitor.h =================================================================== diff -u -rab32897e61cc637a1e28d9dc3f0489b8d16a429c -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/ClipboardMonitor.h (.../ClipboardMonitor.h) (revision ab32897e61cc637a1e28d9dc3f0489b8d16a429c) +++ src/ch/ClipboardMonitor.h (.../ClipboardMonitor.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -22,15 +22,18 @@ #ifndef __CLIPBOARDMONITOR_H__ #define __CLIPBOARDMONITOR_H__ -class CTaskArray; +namespace chcore +{ + class CTaskArray; +} class CClipboardMonitor { public: - static void StartMonitor(CTaskArray* pTasks); + static void StartMonitor(chcore::CTaskArray* pTasks); static void StopMonitor(); - void Start(CTaskArray* pTasks); + void Start(chcore::CTaskArray* pTasks); void Stop(); protected: @@ -42,7 +45,7 @@ protected: static CClipboardMonitor S_ClipboardMonitor; - CTaskArray* m_pTasks; + chcore::CTaskArray* m_pTasks; // thread control chcore::TWorkerThreadController m_threadWorker; Index: src/ch/MainWnd.cpp =================================================================== diff -u -rfb4c4006dee5aaf815d08bc3e89312445b994307 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision fb4c4006dee5aaf815d08bc3e89312445b994307) +++ src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -74,7 +74,8 @@ m_pFeedbackFactory(CFeedbackHandlerFactory::CreateFactory()), m_pdlgStatus(NULL), m_pdlgMiniView(NULL), - m_dwLastTime(0) + m_dwLastTime(0), + m_tasks() { } @@ -380,7 +381,7 @@ ///////////////////////////////////////////////////////////////////////////// // CMainWnd/CTrayIcon menu message handlers -void CMainWnd::ShowStatusWindow(const CTaskPtr& spSelect) +void CMainWnd::ShowStatusWindow(const chcore::CTaskPtr& spSelect) { m_pdlgStatus=new CStatusDlg(&m_tasks, this); // self deleting m_pdlgStatus->m_spInitialSelection = spSelect; @@ -501,7 +502,7 @@ chcore::SetTaskPropValue(tTaskDefinition.GetConfiguration(), GetResManager().LoadString(IDS_NEXTCOPY_STRING)); // create task with the above definition - CTaskPtr spTask = m_tasks.CreateTask(tTaskDefinition); + chcore::CTaskPtr spTask = m_tasks.CreateTask(tTaskDefinition); // add to task list and start processing spTask->BeginProcessing(); @@ -549,7 +550,7 @@ try { - CTaskPtr spTask = m_tasks.ImportTask(strPath); + chcore::CTaskPtr spTask = m_tasks.ImportTask(strPath); if(spTask) spTask->Store(); bImported = true; @@ -611,7 +612,7 @@ chcore::SetTaskPropValue(tTaskDefinition.GetConfiguration(), GetResManager().LoadString(IDS_NEXTCOPY_STRING)); // new task - CTaskPtr spTask = m_tasks.CreateTask(tTaskDefinition); + chcore::CTaskPtr spTask = m_tasks.CreateTask(tTaskDefinition); // start spTask->BeginProcessing(); @@ -624,7 +625,7 @@ { case WM_MINIVIEWDBLCLK: { - CTaskPtr spTask = m_tasks.GetTaskBySessionUniqueID(lParam); + chcore::CTaskPtr spTask = m_tasks.GetTaskBySessionUniqueID(lParam); ShowStatusWindow(spTask); break; } Index: src/ch/MainWnd.h =================================================================== diff -u -r633a533cb6e741d44fe28aa56339e1d2709b1b27 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/MainWnd.h (.../MainWnd.h) (revision 633a533cb6e741d44fe28aa56339e1d2709b1b27) +++ src/ch/MainWnd.h (.../MainWnd.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -22,8 +22,8 @@ #include "TrayIcon.h" #include "structs.h" -#include "task.h" -#include "..\libchcore\TSharedMemory.h" +#include "../libchcore/task.h" +#include "../libchcore/TSharedMemory.h" class CMiniViewDlg; class CStatusDlg; @@ -40,7 +40,7 @@ public: CTrayIcon m_ctlTray; - CTaskArray m_tasks; + chcore::CTaskArray m_tasks; chcore::IFeedbackHandlerFactory* m_pFeedbackFactory; chcore::TSharedMemory m_tCHExtharedMemory; @@ -68,7 +68,7 @@ protected: BOOL RegisterClass(); int ShowTrayIcon(); - void ShowStatusWindow(const CTaskPtr& spSelect = CTaskPtr()); + void ShowStatusWindow(const chcore::CTaskPtr& spSelect = chcore::CTaskPtr()); void PrepareToExit(); void ProcessCommandLine(const TCommandLineParser& rCommandLine); Index: src/ch/MiniViewDlg.cpp =================================================================== diff -u -r0a673d59b6baab3d616ce2570e5bf63378fa7e3c -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/MiniViewDlg.cpp (.../MiniViewDlg.cpp) (revision 0a673d59b6baab3d616ce2570e5bf63378fa7e3c) +++ src/ch/MiniViewDlg.cpp (.../MiniViewDlg.cpp) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -17,6 +17,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "stdafx.h" +#include "../libchcore/task.h" #include "MiniViewDlg.h" #include "ch.h" #include @@ -41,7 +42,7 @@ ///////////////////////////////////////////////////////////////////////////// // CMiniViewDlg dialog -CMiniViewDlg::CMiniViewDlg(CTaskArray* pArray, bool *pbHide, CWnd* pParent /*=NULL*/) +CMiniViewDlg::CMiniViewDlg(chcore::CTaskArray* pArray, bool *pbHide, CWnd* pParent /*=NULL*/) :ictranslate::CLanguageDialog(IDD_MINIVIEW_DIALOG, pParent, &m_bLock) { //{{AFX_DATA_INIT(CMiniViewDlg) @@ -183,19 +184,19 @@ { for(size_t stIndex = 0; stIndex < m_pTasks->GetSize(); ++stIndex) { - CTaskPtr spTask = m_pTasks->GetAt(stIndex); + chcore::CTaskPtr spTask = m_pTasks->GetAt(stIndex); spTask->GetMiniSnapshot(&m_tMiniDisplayData); - if(m_tMiniDisplayData.m_eTaskState != eTaskState_Finished && m_tMiniDisplayData.m_eTaskState != eTaskState_Cancelled) + if(m_tMiniDisplayData.m_eTaskState != chcore::eTaskState_Finished && m_tMiniDisplayData.m_eTaskState != chcore::eTaskState_Cancelled) { pItem = m_ctlStatus.GetItemAddress(index++); // load - if(m_tMiniDisplayData.m_eTaskState == eTaskState_Error) + if(m_tMiniDisplayData.m_eTaskState == chcore::eTaskState_Error) pItem->m_crColor=RGB(255, 0, 0); - else if(m_tMiniDisplayData.m_eTaskState == eTaskState_Paused) + else if(m_tMiniDisplayData.m_eTaskState == chcore::eTaskState_Paused) pItem->m_crColor=RGB(255, 255, 0); - else if(m_tMiniDisplayData.m_eTaskState == eTaskState_Waiting) + else if(m_tMiniDisplayData.m_eTaskState == chcore::eTaskState_Waiting) pItem->m_crColor=RGB(50, 50, 50); else pItem->m_crColor=RGB(0, 255, 0); @@ -409,7 +410,7 @@ if (iSel == LB_ERR || (size_t)iSel >= pDlg->m_ctlStatus.m_vItems.size()) return; - CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; + chcore::CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; if(spTask) spTask->PauseProcessing(); else @@ -516,10 +517,10 @@ int iSel=pDlg->m_ctlStatus.GetCurSel(); if (iSel == LB_ERR || (size_t)iSel >= pDlg->m_ctlStatus.m_vItems.size()) return; - CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; + chcore::CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; if (spTask) { - if(spTask->GetTaskState() == eTaskState_Waiting) + if(spTask->GetTaskState() == chcore::eTaskState_Waiting) spTask->SetForceFlag(true); else spTask->ResumeProcessing(); @@ -560,7 +561,7 @@ int iSel=pDlg->m_ctlStatus.GetCurSel(); if (iSel == LB_ERR || (size_t)iSel >= pDlg->m_ctlStatus.m_vItems.size()) return; - CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; + chcore::CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; if(spTask) spTask->CancelProcessing(); else @@ -614,7 +615,7 @@ int iSel=pDlg->m_ctlStatus.GetCurSel(); if (iSel == LB_ERR || (size_t)iSel >= pDlg->m_ctlStatus.m_vItems.size()) return; - CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; + chcore::CTaskPtr spTask = pDlg->m_ctlStatus.m_vItems.at(iSel)->m_spTask; if(spTask) spTask->RestartProcessing(); else @@ -808,7 +809,7 @@ if(iSel == LB_ERR || (size_t)iSel >= m_ctlStatus.m_vItems.size()) return; - CTaskPtr spTask = m_ctlStatus.m_vItems.at(iSel)->m_spTask; + chcore::CTaskPtr spTask = m_ctlStatus.m_vItems.at(iSel)->m_spTask; if(spTask) GetParent()->PostMessage(WM_MINIVIEWDBLCLK, 0, (LPARAM)spTask->GetSessionUniqueID()); else Index: src/ch/MiniViewDlg.h =================================================================== diff -u -r22573f5fa8bfbf68a19deb7631962e026f028045 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/MiniViewDlg.h (.../MiniViewDlg.h) (revision 22573f5fa8bfbf68a19deb7631962e026f028045) +++ src/ch/MiniViewDlg.h (.../MiniViewDlg.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -21,9 +21,13 @@ ///////////////////////////////////////////////////////////////////////////// // CMiniViewDlg dialog -#include "task.h" #include "ProgressListBox.h" +namespace chcore +{ + class chcore::CTaskArray; +} + #define BTN_COUNT 5 #define MSG_DRAWBUTTON 1 @@ -47,7 +51,7 @@ // Construction public: - CMiniViewDlg(CTaskArray* pArray, bool* pbHide, CWnd* pParent = NULL); // standard constructor + CMiniViewDlg(chcore::CTaskArray* pArray, bool* pbHide, CWnd* pParent = NULL); // standard constructor void ShowWindow(); void HideWindow(); @@ -65,15 +69,15 @@ virtual void OnLanguageChanged(); // from CMainWnd - CTaskArray *m_pTasks; + chcore::CTaskArray *m_pTasks; CBrush m_brBackground; int m_iLastHeight; bool m_bShown; _PROGRESSITEM_ item; // cache - TASK_MINI_DISPLAY_DATA m_tMiniDisplayData; + chcore::TASK_MINI_DISPLAY_DATA m_tMiniDisplayData; bool m_bActive; // lock Index: src/ch/ProgressListBox.cpp =================================================================== diff -u -rc435ab507c8b8280264188b49e9ada56d46c0261 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/ProgressListBox.cpp (.../ProgressListBox.cpp) (revision c435ab507c8b8280264188b49e9ada56d46c0261) +++ src/ch/ProgressListBox.cpp (.../ProgressListBox.cpp) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -17,7 +17,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "stdafx.h" -#include "task.h" +#include "../libchcore/task.h" #include "ProgressListBox.h" #include "MemDC.h" Index: src/ch/ProgressListBox.h =================================================================== diff -u -rf703b71b8c856e2538283555e9fdbc84918677c3 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/ProgressListBox.h (.../ProgressListBox.h) (revision f703b71b8c856e2538283555e9fdbc84918677c3) +++ src/ch/ProgressListBox.h (.../ProgressListBox.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -30,7 +30,7 @@ COLORREF m_crColor; - CTaskPtr m_spTask; + chcore::CTaskPtr m_spTask; }; class CProgressListBox : public CListBox Index: src/ch/StatusDlg.cpp =================================================================== diff -u -r6df9b4cff81dedf8c5571a98702b584b061eac09 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/StatusDlg.cpp (.../StatusDlg.cpp) (revision 6df9b4cff81dedf8c5571a98702b584b061eac09) +++ src/ch/StatusDlg.cpp (.../StatusDlg.cpp) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -18,6 +18,7 @@ ***************************************************************************/ #include "stdafx.h" #include "ch.h" +#include "../libchcore/task.h" #include "resource.h" #include "StatusDlg.h" #include "BufferSizeDlg.h" @@ -36,7 +37,7 @@ ///////////////////////////////////////////////////////////////////////////// // CStatusDlg dialog -CStatusDlg::CStatusDlg(CTaskArray* pTasks, CWnd* pParent /*=NULL*/) +CStatusDlg::CStatusDlg(chcore::CTaskArray* pTasks, CWnd* pParent /*=NULL*/) : ictranslate::CLanguageDialog(CStatusDlg::IDD, pParent, &m_bLock) { //{{AFX_DATA_INIT(CStatusDlg) @@ -215,7 +216,7 @@ CLanguageDialog::OnTimer(nIDEvent); } -void CStatusDlg::AddTaskInfo(int nPos, const CTaskPtr& spTask, DWORD dwCurrentTime) +void CStatusDlg::AddTaskInfo(int nPos, const chcore::CTaskPtr& spTask, DWORD dwCurrentTime) { _ASSERTE(spTask != NULL); if(spTask == NULL) @@ -225,7 +226,7 @@ _itot(nPos, m_szData, 10); // get data snapshot from task - TASK_DISPLAY_DATA td; + chcore::TASK_DISPLAY_DATA td; spTask->GetSnapshot(&td); // index subitem @@ -337,7 +338,7 @@ void CStatusDlg::OnSetBuffersizeButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(!spTask) return; @@ -348,7 +349,7 @@ spTask->SetBufferSizes(dlg.m_bsSizes); } -CTaskPtr CStatusDlg::GetSelectedItemPointer() +chcore::CTaskPtr CStatusDlg::GetSelectedItemPointer() { // returns ptr to a CTask for a given element in listview if(m_ctlStatusList.GetSelectedCount() == 1) @@ -358,7 +359,7 @@ return m_pTasks->GetTaskBySessionUniqueID(m_ctlStatusList.GetItemData(nPos)); } - return CTaskPtr(); + return chcore::CTaskPtr(); } void CStatusDlg::OnRollUnrollButton() @@ -420,7 +421,7 @@ GetDlgItem(IDC_SHOW_LOG_BUTTON)->EnableWindow(true); GetDlgItem(IDC_DELETE_BUTTON)->EnableWindow(true); - if (m_spSelectedItem->GetTaskState() == eTaskState_Finished || m_spSelectedItem->GetTaskState() == eTaskState_Cancelled) + if (m_spSelectedItem->GetTaskState() == chcore::eTaskState_Finished || m_spSelectedItem->GetTaskState() == chcore::eTaskState_Cancelled) { GetDlgItem(IDC_CANCEL_BUTTON)->EnableWindow(false); GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(false); @@ -429,15 +430,15 @@ else { // pause/resume - if (m_spSelectedItem->GetTaskState() == eTaskState_Paused) + if (m_spSelectedItem->GetTaskState() == chcore::eTaskState_Paused) { GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(false); GetDlgItem(IDC_RESUME_BUTTON)->EnableWindow(true); } else { GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(true); - if (m_spSelectedItem->GetTaskState() == eTaskState_Waiting) + if (m_spSelectedItem->GetTaskState() == chcore::eTaskState_Waiting) GetDlgItem(IDC_RESUME_BUTTON)->EnableWindow(true); else GetDlgItem(IDC_RESUME_BUTTON)->EnableWindow(false); @@ -527,7 +528,7 @@ void CStatusDlg::OnPauseButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(spTask) { TRACE("PauseProcessing call...\n"); @@ -539,10 +540,10 @@ void CStatusDlg::OnResumeButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(spTask) { - if(spTask->GetTaskState() == eTaskState_Waiting) + if(spTask->GetTaskState() == chcore::eTaskState_Waiting) spTask->SetForceFlag(); else spTask->ResumeProcessing(); @@ -553,7 +554,7 @@ void CStatusDlg::OnCancelButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(spTask) { spTask->CancelProcessing(); @@ -563,7 +564,7 @@ void CStatusDlg::OnRestartButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(spTask) { spTask->RestartProcessing(); @@ -573,11 +574,11 @@ void CStatusDlg::OnDeleteButton() { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if(spTask) { - ETaskCurrentState eTaskState = spTask->GetTaskState(); - if(eTaskState != eTaskState_Finished && eTaskState != eTaskState_Cancelled) + chcore::ETaskCurrentState eTaskState = spTask->GetTaskState(); + if(eTaskState != chcore::eTaskState_Finished && eTaskState != chcore::eTaskState_Cancelled) { // ask if cancel if(MsgBox(IDS_CONFIRMCANCEL_STRING, MB_OKCANCEL | MB_ICONQUESTION) == IDOK) @@ -638,11 +639,11 @@ break; case VK_SPACE: { - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if (!spTask) return; - if(spTask->GetTaskState() == eTaskState_Paused) + if(spTask->GetTaskState() == chcore::eTaskState_Paused) OnResumeButton(); else OnPauseButton(); @@ -653,19 +654,19 @@ *pResult = 0; } -int CStatusDlg::GetImageFromStatus(ETaskCurrentState eState) +int CStatusDlg::GetImageFromStatus(chcore::ETaskCurrentState eState) { switch(eState) { - case eTaskState_Cancelled: + case chcore::eTaskState_Cancelled: return 4; - case eTaskState_Finished: + case chcore::eTaskState_Finished: return 3; - case eTaskState_Waiting: + case chcore::eTaskState_Waiting: return 5; - case eTaskState_Paused: + case chcore::eTaskState_Paused: return 2; - case eTaskState_Error: + case chcore::eTaskState_Error: return 1; default: return 0; @@ -779,16 +780,16 @@ void CStatusDlg::OnShowLogButton() { // show log - CTaskPtr spTask = GetSelectedItemPointer(); + chcore::CTaskPtr spTask = GetSelectedItemPointer(); if (!spTask) return; - unsigned long lResult = (unsigned long)(ShellExecute(this->m_hWnd, _T("open"), _T("notepad.exe"), spTask->GetRelatedPath(CTask::ePathType_TaskLogFile).ToString(), NULL, SW_SHOWNORMAL)); + unsigned long lResult = (unsigned long)(ShellExecute(this->m_hWnd, _T("open"), _T("notepad.exe"), spTask->GetRelatedPath(chcore::CTask::ePathType_TaskLogFile).ToString(), NULL, SW_SHOWNORMAL)); if(lResult < 32) { ictranslate::CFormat fmt(GetResManager().LoadString(IDS_SHELLEXECUTEERROR_STRING)); fmt.SetParam(_t("%errno"), lResult); - fmt.SetParam(_t("%path"), spTask->GetRelatedPath(CTask::ePathType_TaskLogFile).ToString()); + fmt.SetParam(_t("%path"), spTask->GetRelatedPath(chcore::CTask::ePathType_TaskLogFile).ToString()); AfxMessageBox(fmt); } } @@ -965,50 +966,50 @@ InitializeResizableControls(); } -CString CStatusDlg::GetStatusString(const TASK_DISPLAY_DATA& rTaskDisplayData) +CString CStatusDlg::GetStatusString(const chcore::TASK_DISPLAY_DATA& rTaskDisplayData) { CString strStatusText; // status string // first switch(rTaskDisplayData.m_eTaskState) { - case eTaskState_Error: + case chcore::eTaskState_Error: { strStatusText = GetResManager().LoadString(IDS_STATUS_ERROR_STRING); strStatusText += _T("/"); break; } - case eTaskState_Paused: + case chcore::eTaskState_Paused: { strStatusText = GetResManager().LoadString(IDS_STATUS_PAUSED_STRING); strStatusText += _T("/"); break; } - case eTaskState_Finished: + case chcore::eTaskState_Finished: { strStatusText = GetResManager().LoadString(IDS_STATUS_FINISHED_STRING); strStatusText += _T("/"); break; } - case eTaskState_Waiting: + case chcore::eTaskState_Waiting: { strStatusText = GetResManager().LoadString(IDS_STATUS_WAITING_STRING); strStatusText += _T("/"); break; } - case eTaskState_Cancelled: + case chcore::eTaskState_Cancelled: { strStatusText = GetResManager().LoadString(IDS_STATUS_CANCELLED_STRING); strStatusText += _T("/"); break; } - case eTaskState_None: + case chcore::eTaskState_None: { strStatusText = GetResManager().LoadString(IDS_STATUS_INITIALIZING_STRING); strStatusText += _T("/"); break; } - case eTaskState_Processing: + case chcore::eTaskState_Processing: break; default: BOOST_ASSERT(false); // not implemented state Index: src/ch/StatusDlg.h =================================================================== diff -u -r0a673d59b6baab3d616ce2570e5bf63378fa7e3c -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/StatusDlg.h (.../StatusDlg.h) (revision 0a673d59b6baab3d616ce2570e5bf63378fa7e3c) +++ src/ch/StatusDlg.h (.../StatusDlg.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -19,9 +19,15 @@ #ifndef __STATUSDLG_H__ #define __STATUSDLG_H__ -#include "task.h" #include "FFListCtrl.h" +namespace chcore +{ + class CTaskArray; + class CTask; + typedef boost::shared_ptr CTaskPtr; +} + #define WM_UPDATESTATUS WM_USER+6 #define WM_STATUSCLOSING WM_USER+12 @@ -33,20 +39,20 @@ // Construction public: - CStatusDlg(CTaskArray* pTasks, CWnd* pParent = NULL); // standard constructor + CStatusDlg(chcore::CTaskArray* pTasks, CWnd* pParent = NULL); // standard constructor ~CStatusDlg(); void PostCloseMessage(); void SetBufferSizesString(UINT uiValue, int iIndex); void RefreshStatus(); LPTSTR FormatTime(time_t timeSeconds, LPTSTR lpszBuffer, size_t stMaxBufferSize); - int GetImageFromStatus(ETaskCurrentState eState); + int GetImageFromStatus(chcore::ETaskCurrentState eState); void ApplyButtonsState(); void ApplyDisplayDetails(bool bInitial=false); - CTaskPtr GetSelectedItemPointer(); + chcore::CTaskPtr GetSelectedItemPointer(); - void AddTaskInfo(int nPos, const CTaskPtr& spTask, DWORD dwCurrentTime); + void AddTaskInfo(int nPos, const chcore::CTaskPtr& spTask, DWORD dwCurrentTime); void EnableControls(bool bEnable=true); protected: @@ -57,7 +63,7 @@ virtual void OnLanguageChanged(); void PrepareResizableControls(); - CString GetStatusString(const TASK_DISPLAY_DATA& rTaskDisplayData); + CString GetStatusString(const chcore::TASK_DISPLAY_DATA& rTaskDisplayData); virtual BOOL OnInitDialog(); afx_msg void OnTimer(UINT_PTR nIDEvent); @@ -83,14 +89,14 @@ DECLARE_MESSAGE_MAP() public: - CTaskPtr m_spInitialSelection; + chcore::CTaskPtr m_spInitialSelection; static bool m_bLock; // locker protected: - CTaskArray* m_pTasks; - CTaskPtr m_spSelectedItem; - CTaskPtr m_spLastSelected; + chcore::CTaskArray* m_pTasks; + chcore::CTaskPtr m_spSelectedItem; + chcore::CTaskPtr m_spLastSelected; TCHAR m_szData[_MAX_PATH]; TCHAR m_szTimeBuffer1[40]; Index: src/ch/Stdafx.h =================================================================== diff -u -r4be0f47d68a1a161529dc55901659b9daec996e3 -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/Stdafx.h (.../Stdafx.h) (revision 4be0f47d68a1a161529dc55901659b9daec996e3) +++ src/ch/Stdafx.h (.../Stdafx.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -46,7 +46,6 @@ #include "debug.h" #include "../libicpf/exception.h" #include "../libictranslate/LanguageDialog.h" -#include "../common/ErrorConstants.h" #include "../libchcore/TLogger.h" #include "../libchcore/TConfigSerializers.h" Index: src/ch/ch.vc90.vcproj =================================================================== diff -u -r4d20d0e58f37f06ac91287015b960308db54d47e -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) +++ src/ch/ch.vc90.vcproj (.../ch.vc90.vcproj) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -426,14 +426,6 @@ RelativePath="structs.h" > - - - - Index: src/libchcore/ErrorCodes.h =================================================================== diff -u -r4d20d0e58f37f06ac91287015b960308db54d47e -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) +++ src/libchcore/ErrorCodes.h (.../ErrorCodes.h) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -66,10 +66,15 @@ eErr_NodeDoesNotExist = 2504, eErr_UnsupportedMultipleSubnodesLevels = 2505, eErr_CannotWriteArchive = 2506, + eErr_InvalidSerializationData = 2507, // Filesystem errors eErr_FixedDriveWithoutDriveLetter = 3000, eErr_CannotGetFileInfo = 3001, + + // Task handling errors + eErr_MissingTaskSerializationPath = 4000, + }; END_CHCORE_NAMESPACE Index: src/libchcore/libchcore.vc90.vcproj =================================================================== diff -u -r4d20d0e58f37f06ac91287015b960308db54d47e -r0cf74c78280b58c363868caafb9bf493a57aa006 --- src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision 4d20d0e58f37f06ac91287015b960308db54d47e) +++ src/libchcore/libchcore.vc90.vcproj (.../libchcore.vc90.vcproj) (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -364,6 +364,14 @@ > + + + + Index: src/libchcore/task.cpp =================================================================== diff -u --- src/libchcore/task.cpp (revision 0) +++ src/libchcore/task.cpp (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -0,0 +1,1274 @@ +/*************************************************************************** +* 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. * +***************************************************************************/ +#include "Stdafx.h" +#include "task.h" + +#pragma warning(push) +#pragma warning(disable: 4996) + #include + #include + #include +#pragma warning(pop) + +#include +#include "TTaskConfiguration.h" +#include "TSubTaskContext.h" +#include "TLocalFilesystem.h" +#include "TSubTaskScanDirectory.h" +#include "TSubTaskCopyMove.h" +#include "TSubTaskDelete.h" +#include "TBinarySerializer.h" +#include "SerializationHelpers.h" +#include +#include +#include "../libicpf/exception.h" +#include +#include "TLogger.h" + +BEGIN_CHCORE_NAMESPACE + +//////////////////////////////////////////////////////////////////////////// +// CTask members + +CTask::CTask(IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID) : + m_log(), + m_piFeedbackHandler(piFeedbackHandler), + m_arrSourcePathsInfo(m_tTaskDefinition.GetSourcePaths()), + m_files(m_tTaskDefinition.GetSourcePaths()), + m_bForce(false), + m_bContinue(false), + m_bRareStateModified(false), + m_bOftenStateModified(false), + m_stSessionUniqueID(stSessionUniqueID), + m_localStats(), + m_eCurrentState(eTaskState_None) +{ + BOOST_ASSERT(piFeedbackHandler); +} + +CTask::~CTask() +{ + KillThread(); + if(m_piFeedbackHandler) + m_piFeedbackHandler->Delete(); +} + +void CTask::SetTaskDefinition(const TTaskDefinition& rTaskDefinition) +{ + m_tTaskDefinition = rTaskDefinition; + + m_arrSourcePathsInfo.SetCount(m_tTaskDefinition.GetSourcePathCount()); + m_files.Clear(); +} + +void CTask::OnRegisterTask(TTasksGlobalStats& rtGlobalStats) +{ + m_localStats.ConnectGlobalStats(rtGlobalStats); +} + +void CTask::OnUnregisterTask() +{ + m_localStats.DisconnectGlobalStats(); +} + +void CTask::SetTaskState(ETaskCurrentState eTaskState) +{ + // NOTE: we could check some transition rules here + boost::unique_lock lock(m_lock); + m_eCurrentState = eTaskState; +} + +ETaskCurrentState CTask::GetTaskState() const +{ + boost::shared_lock lock(m_lock); + return m_eCurrentState; +} + +void CTask::SetBufferSizes(const TBufferSizes& bsSizes) +{ + m_tTaskDefinition.GetConfiguration().DelayNotifications(); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.GetDefaultSize()); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.GetOneDiskSize()); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.GetTwoDisksSize()); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.GetCDSize()); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.GetLANSize()); + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), bsSizes.IsOnlyDefault()); + m_tTaskDefinition.GetConfiguration().ResumeNotifications(); +} + +void CTask::GetBufferSizes(TBufferSizes& bsSizes) +{ + bsSizes.SetDefaultSize(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + bsSizes.SetOneDiskSize(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + bsSizes.SetTwoDisksSize(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + bsSizes.SetCDSize(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + bsSizes.SetLANSize(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + bsSizes.SetOnlyDefault(GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); +} + +int CTask::GetCurrentBufferIndex() +{ + return m_localStats.GetCurrentBufferIndex(); +} + +// thread +void CTask::SetPriority(int nPriority) +{ + SetTaskPropValue(m_tTaskDefinition.GetConfiguration(), nPriority); +} + +void CTask::CalculateProcessedSize() +{ + boost::shared_lock lock(m_lock); + CalculateProcessedSizeNL(); +} + +void CTask::CalculateProcessedSizeNL() +{ + m_localStats.SetProcessedSize(m_files.CalculatePartialSize(m_tTaskBasicProgressInfo.GetCurrentIndex())); +} + +void CTask::Load(const TSmartPath& strPath) +{ + using Serializers::Serialize; + + boost::unique_lock lock(m_lock); + + //////////////////////////////// + // First load task description + m_tTaskDefinition.Load(strPath); + m_strFilePath = strPath; + + // update members according to the task definition + // make sure to resize paths info array size to match source paths count + m_arrSourcePathsInfo.SetCount(m_tTaskDefinition.GetSourcePathCount()); + GetTaskPropValue(m_tTaskDefinition.GetConfiguration(), m_afFilters); + + //////////////////////////////// + // now rarely changing task progress data + TSmartPath pathRarelyChangingPath = GetRelatedPathNL(ePathType_TaskRarelyChangingState); + TReadBinarySerializer readSerializer; + readSerializer.Init(pathRarelyChangingPath); + + m_arrSourcePathsInfo.Serialize(readSerializer, true); + m_files.Serialize(readSerializer, false); + + CalculateTotalSizeNL(); + + /////////////////////////////////// + // and often changing data + TSmartPath pathOftenChangingPath = GetRelatedPathNL(ePathType_TaskOftenChangingState); + readSerializer.Init(pathOftenChangingPath); + + Serialize(readSerializer, m_tTaskBasicProgressInfo); + + CalculateProcessedSizeNL(); + + // load task state, convert "waiting" state to "processing" + int iState = eTaskState_None; + Serialize(readSerializer, iState); + if(iState >= eTaskState_None && iState < eTaskState_Max) + { + if(iState == eTaskState_Waiting) + iState = eTaskState_Processing; + m_eCurrentState = (ETaskCurrentState)iState; + } + else + { + BOOST_ASSERT(false); + THROW_CORE_EXCEPTION(eErr_InvalidSerializationData); + } + + time_t timeElapsed = 0; + Serialize(readSerializer, timeElapsed); + m_localStats.SetTimeElapsed(timeElapsed); + + m_arrSourcePathsInfo.Serialize(readSerializer, false); + m_files.Serialize(readSerializer, true); +} + +void CTask::Store() +{ + using Serializers::Serialize; + + boost::upgrade_lock lock(m_lock); + + BOOST_ASSERT(!m_strTaskDirectory.IsEmpty()); + if(m_strTaskDirectory.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_MissingTaskSerializationPath); + + // generate file path if not available yet + if(m_strFilePath.IsEmpty()) + { + boost::upgrade_to_unique_lock upgraded_lock(lock); + m_strFilePath = m_strTaskDirectory + PathFromWString(m_tTaskDefinition.GetTaskUniqueID() + _T(".cht")); + } + + // store task definition only if changed + m_tTaskDefinition.Store(GetRelatedPathNL(ePathType_TaskDefinition), true); + + // rarely changing data + if(m_bRareStateModified) + { + TWriteBinarySerializer writeSerializer; + writeSerializer.Init(GetRelatedPathNL(ePathType_TaskRarelyChangingState)); + + m_arrSourcePathsInfo.Serialize(writeSerializer, true); + + ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex()); + if(eSubOperation != eSubOperation_Scanning) + m_files.Serialize(writeSerializer, false); + else + { + size_t stFakeSize(0); + Serialize(writeSerializer, stFakeSize); + } + } + + if(m_bOftenStateModified) + { + TWriteBinarySerializer writeSerializer; + writeSerializer.Init(GetRelatedPathNL(ePathType_TaskOftenChangingState)); + + Serialize(writeSerializer, m_tTaskBasicProgressInfo); + + // store current state (convert from waiting to processing state before storing) + int iState = m_eCurrentState; + if(iState == eTaskState_Waiting) + iState = eTaskState_Processing; + + Serialize(writeSerializer, iState); + + time_t timeElapsed = m_localStats.GetTimeElapsed(); + Serialize(writeSerializer, timeElapsed); + + m_arrSourcePathsInfo.Serialize(writeSerializer, false); + + ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex()); + if(eSubOperation != eSubOperation_Scanning) + m_files.Serialize(writeSerializer, true); + else + { + size_t stFakeSize(0); + Serialize(writeSerializer, stFakeSize); + } + } +} + +void CTask::KillThread() +{ + m_workerThread.StopThread(); +} + +void CTask::BeginProcessing() +{ + boost::unique_lock lock(m_lock); + + m_bRareStateModified = true; + m_bOftenStateModified = true; + + m_workerThread.StartThread(DelegateThreadProc, this, GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); +} + +void CTask::ResumeProcessing() +{ + // the same as retry but less demanding + if(GetTaskState() == eTaskState_Paused) + { + SetTaskState(eTaskState_Processing); + BeginProcessing(); + } +} + +bool CTask::RetryProcessing() +{ + // retry used to auto-resume, after loading + if(GetTaskState() != eTaskState_Paused && GetTaskState() != eTaskState_Finished && GetTaskState() != eTaskState_Cancelled) + { + BeginProcessing(); + return true; + } + return false; +} + +void CTask::RestartProcessing() +{ + KillThread(); + + SetTaskState(eTaskState_None); + + m_localStats.SetTimeElapsed(0); + m_tTaskBasicProgressInfo.SetCurrentIndex(0); + + BeginProcessing(); +} + +void CTask::PauseProcessing() +{ + if(GetTaskState() != eTaskState_Finished && GetTaskState() != eTaskState_Cancelled) + { + KillThread(); + SetTaskState(eTaskState_Paused); + + m_bOftenStateModified = true; + } +} + +void CTask::CancelProcessing() +{ + // change to ST_CANCELLED + if(GetTaskState() != eTaskState_Finished) + { + KillThread(); + SetTaskState(eTaskState_Cancelled); + m_bOftenStateModified = true; + } +} + +void CTask::GetMiniSnapshot(TASK_MINI_DISPLAY_DATA *pData) +{ + boost::shared_lock lock(m_lock); + size_t stCurrentIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); + + if(stCurrentIndex < m_files.GetSize()) + pData->m_strPath = m_files.GetAt(stCurrentIndex)->GetFullFilePath().GetFileName().ToString(); + else + { + if(m_files.GetSize() > 0) + pData->m_strPath = m_files.GetAt(0)->GetFullFilePath().GetFileName().ToString(); + else + { + if(m_tTaskDefinition.GetSourcePathCount() > 0) + pData->m_strPath = m_tTaskDefinition.GetSourcePathAt(0).GetFileName().ToString(); + else + pData->m_strPath.Clear(); + } + } + + pData->m_eTaskState = m_eCurrentState; + + // percents + pData->m_nPercent = m_localStats.GetProgressInPercent(); +} + +void CTask::GetSnapshot(TASK_DISPLAY_DATA *pData) +{ + boost::unique_lock lock(m_lock); + + size_t stCurrentIndex = m_tTaskBasicProgressInfo.GetCurrentIndex(); + if(stCurrentIndex < m_files.GetSize()) + { + pData->m_strFullFilePath = m_files.GetAt(stCurrentIndex)->GetFullFilePath().ToString(); + pData->m_strFileName = m_files.GetAt(stCurrentIndex)->GetFullFilePath().GetFileName().ToString(); + } + else + { + if(m_files.GetSize() > 0) + { + pData->m_strFullFilePath = m_files.GetAt(0)->GetFullFilePath().ToString(); + pData->m_strFileName = m_files.GetAt(0)->GetFullFilePath().GetFileName().ToString(); + } + else + { + if(m_tTaskDefinition.GetSourcePathCount() > 0) + { + pData->m_strFullFilePath = m_tTaskDefinition.GetSourcePathAt(0).ToString(); + pData->m_strFileName = m_tTaskDefinition.GetSourcePathAt(0).GetFileName().ToString(); + } + else + { + pData->m_strFullFilePath.Clear(); + pData->m_strFileName.Clear(); + } + } + } + + pData->m_nPriority = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + pData->m_pathDstPath = m_tTaskDefinition.GetDestinationPath(); + pData->m_pafFilters = &m_afFilters; + pData->m_eTaskState = m_eCurrentState; + pData->m_stIndex = stCurrentIndex; + pData->m_ullProcessedSize = m_localStats.GetProcessedSize(); + pData->m_stSize=m_files.GetSize(); + pData->m_ullSizeAll = m_localStats.GetTotalSize(); + pData->m_strUniqueName = m_tTaskDefinition.GetTaskUniqueID(); + pData->m_eOperationType = m_tTaskDefinition.GetOperationType(); + pData->m_eSubOperationType = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex()); + + pData->m_bIgnoreDirectories = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + pData->m_bCreateEmptyFiles = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + + if(m_files.GetSize() > 0) + pData->m_iCurrentBufferIndex = m_localStats.GetCurrentBufferIndex(); + else + pData->m_iCurrentBufferIndex = TBufferSizes::eBuffer_Default; + + switch(pData->m_iCurrentBufferIndex) + { + case TBufferSizes::eBuffer_Default: + pData->m_iCurrentBufferSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + break; + case TBufferSizes::eBuffer_OneDisk: + pData->m_iCurrentBufferSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + break; + case TBufferSizes::eBuffer_TwoDisks: + pData->m_iCurrentBufferSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + break; + case TBufferSizes::eBuffer_CD: + pData->m_iCurrentBufferSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + break; + case TBufferSizes::eBuffer_LAN: + pData->m_iCurrentBufferSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + break; + default: + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + //BOOST_ASSERT(false); // assertions are dangerous here, because we're inside critical section + // (and there could be conflict with Get(Mini)Snapshot called OnTimer in several places. + } + + // percents + pData->m_nPercent = m_localStats.GetProgressInPercent(); + + // time + pData->m_timeElapsed = m_localStats.GetTimeElapsed(); +} + +void CTask::DeleteProgress() +{ + TPathContainer vFilesToRemove; + + // separate scope for shared locking + { + boost::shared_lock lock(m_lock); + + vFilesToRemove.Add(GetRelatedPath(ePathType_TaskDefinition)); + vFilesToRemove.Add(GetRelatedPath(ePathType_TaskRarelyChangingState)); + vFilesToRemove.Add(GetRelatedPath(ePathType_TaskOftenChangingState)); + vFilesToRemove.Add(GetRelatedPath(ePathType_TaskLogFile)); + } + + for(size_t stIndex = 0; stIndex < vFilesToRemove.GetCount(); ++stIndex) + { + DeleteFile(vFilesToRemove.GetAt(stIndex).ToString()); + } +} + +bool CTask::CanBegin() +{ + bool bRet=true; + boost::unique_lock lock(m_lock); + + if(GetContinueFlagNL() || GetForceFlagNL()) + { + m_localStats.MarkTaskAsRunning(); + SetForceFlagNL(false); + SetContinueFlagNL(false); + } + else + bRet = false; + + return bRet; +} + +void CTask::SetTaskDirectory(const TSmartPath& strDir) +{ + boost::unique_lock lock(m_lock); + m_strTaskDirectory = strDir; +} + +TSmartPath CTask::GetTaskDirectory() const +{ + boost::shared_lock lock(m_lock); + return m_strTaskDirectory; +} + +void CTask::SetTaskFilePath(const TSmartPath& strFilePath) +{ + boost::unique_lock lock(m_lock); + m_strFilePath = strFilePath; +} + +TSmartPath CTask::GetTaskFilePath() const +{ + boost::shared_lock lock(m_lock); + return m_strFilePath; +} + +void CTask::SetForceFlag(bool bFlag) +{ + boost::unique_lock lock(m_lock); + m_bForce=bFlag; +} + +bool CTask::GetForceFlag() +{ + boost::shared_lock lock(m_lock); + return m_bForce; +} + +void CTask::SetContinueFlag(bool bFlag) +{ + boost::unique_lock lock(m_lock); + m_bContinue=bFlag; +} + +bool CTask::GetContinueFlag() +{ + boost::shared_lock lock(m_lock); + return m_bContinue; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void CTask::CalculateTotalSizeNL() +{ + m_localStats.SetTotalSize(m_files.CalculateTotalSize()); +} + +void CTask::SetForceFlagNL(bool bFlag) +{ + m_bForce=bFlag; +} + +bool CTask::GetForceFlagNL() +{ + return m_bForce; +} + +void CTask::SetContinueFlagNL(bool bFlag) +{ + m_bContinue=bFlag; +} + +bool CTask::GetContinueFlagNL() +{ + return m_bContinue; +} + +TSubTaskBase::ESubOperationResult CTask::CheckForWaitState() +{ + // limiting operation count + SetTaskState(eTaskState_Waiting); + bool bContinue = false; + while(!bContinue) + { + if(CanBegin()) + { + SetTaskState(eTaskState_Processing); + bContinue = true; + + m_log.logi(_T("Finished waiting for begin permission")); + + // return; // skips sleep and kill flag checking + } + + Sleep(50); // not to make it too hard for processor + + if(m_workerThread.KillRequested()) + { + // log + m_log.logi(_T("Kill request while waiting for begin permission (wait state)")); + return TSubTaskBase::eSubResult_KillRequest; + } + } + + return TSubTaskBase::eSubResult_Continue; +} + +DWORD WINAPI CTask::DelegateThreadProc(LPVOID pParam) +{ + BOOST_ASSERT(pParam); + if(!pParam) + return 1; + + CTask* pTask = (CTask*)pParam; + return pTask->ThrdProc(); +} + +DWORD CTask::ThrdProc() +{ + try + { + TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; + + // initialize log file + TSmartPath pathLogFile = GetRelatedPath(ePathType_TaskLogFile); + + m_log.init(pathLogFile.ToString(), 262144, icpf::log_file::level_debug, false, false); + + // start operation + OnBeginOperation(); + + // enable configuration changes tracking + m_tTaskDefinition.GetConfiguration().ConnectToNotifier(TTaskConfigTracker::NotificationProc, &m_cfgTracker); + m_tTaskDefinition.GetConfiguration().ConnectToNotifier(CTask::OnCfgOptionChanged, this); + + // set thread options + HANDLE hThread = GetCurrentThread(); + ::SetThreadPriorityBoost(hThread, GetTaskPropValue(m_tTaskDefinition.GetConfiguration())); + + // determine when to scan directories + bool bReadTasksSize = GetTaskPropValue(m_tTaskDefinition.GetConfiguration()); + + // 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(); + if(!bReadTasksSize || stSubOperationIndex != 0 || m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() == 0 || m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(0) != eSubOperation_Scanning) + eResult = CheckForWaitState(); // operation limiting + + // start tracking time for this thread + m_localStats.EnableTimeTracking(); + + // prepare context for subtasks + TSubTaskContext tSubTaskContext(m_tTaskDefinition, m_arrSourcePathsInfo, m_files, m_localStats, m_tTaskBasicProgressInfo, m_cfgTracker, m_log, m_piFeedbackHandler, m_workerThread, m_fsLocal); + + for(; stSubOperationIndex < m_tTaskDefinition.GetOperationPlan().GetSubOperationsCount() && eResult == TSubTaskBase::eSubResult_Continue; ++stSubOperationIndex) + { + // set current sub-operation index to allow resuming + m_tTaskBasicProgressInfo.SetSubOperationIndex(stSubOperationIndex); + + ESubOperationType eSubOperation = m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(stSubOperationIndex); + switch(eSubOperation) + { + case eSubOperation_Scanning: + { + // start searching + TSubTaskScanDirectories tSubTaskScanDir(tSubTaskContext); + eResult = tSubTaskScanDir.Exec(); + + // if we didn't wait for permission to start earlier, then ask now (but only in case this is the first search) + if(eResult == TSubTaskBase::eSubResult_Continue && bReadTasksSize && stSubOperationIndex == 0) + { + m_localStats.DisableTimeTracking(); + + eResult = CheckForWaitState(); + + m_localStats.EnableTimeTracking(); + } + + break; + } + + case eSubOperation_Copying: + { + TSubTaskCopyMove tSubTaskCopyMove(tSubTaskContext); + + eResult = tSubTaskCopyMove.Exec(); + break; + } + + case eSubOperation_Deleting: + { + TSubTaskDelete tSubTaskDelete(tSubTaskContext); + eResult = tSubTaskDelete.Exec(); + break; + } + + default: + BOOST_ASSERT(false); + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + } + + // change status to finished + if(eResult == TSubTaskBase::eSubResult_Continue) + SetTaskState(eTaskState_Finished); + + // refresh time + m_localStats.DisableTimeTracking(); + + // finishing processing + // change task status + switch(eResult) + { + case TSubTaskBase::eSubResult_Error: + m_piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_OperationError, NULL); + SetTaskState(eTaskState_Error); + break; + + case TSubTaskBase::eSubResult_CancelRequest: + SetTaskState(eTaskState_Cancelled); + break; + + case TSubTaskBase::eSubResult_PauseRequest: + SetTaskState(eTaskState_Paused); + break; + + case TSubTaskBase::eSubResult_KillRequest: + // the only operation + if(GetTaskState() == eTaskState_Waiting) + SetTaskState(eTaskState_Processing); + break; + + case TSubTaskBase::eSubResult_Continue: + m_piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_OperationFinished, NULL); + SetTaskState(eTaskState_Finished); + break; + + default: + BOOST_ASSERT(false); + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } + + // perform cleanup dependent on currently executing subtask + switch(m_tTaskDefinition.GetOperationPlan().GetSubOperationAt(m_tTaskBasicProgressInfo.GetSubOperationIndex())) + { + case eSubOperation_Scanning: + m_files.Clear(); // get rid of m_files contents + m_bRareStateModified = true; + break; + } + + // save progress before killed + m_bOftenStateModified = true; + Store(); + + // reset flags + SetContinueFlag(false); + SetForceFlag(false); + + // mark this task as dead, so other can start + m_localStats.MarkTaskAsNotRunning(); + + m_tTaskDefinition.GetConfiguration().DisconnectFromNotifier(TTaskConfigTracker::NotificationProc); + m_tTaskDefinition.GetConfiguration().DisconnectFromNotifier(CTask::OnCfgOptionChanged); + + // and the real end + OnEndOperation(); + } + catch(...) + { + m_tTaskDefinition.GetConfiguration().DisconnectFromNotifier(TTaskConfigTracker::NotificationProc); + m_tTaskDefinition.GetConfiguration().DisconnectFromNotifier(CTask::OnCfgOptionChanged); + + // refresh time + m_localStats.DisableTimeTracking(); + + // log + m_log.loge(_T("Caught exception in ThrdProc")); + + // let others know some error happened + m_piFeedbackHandler->RequestFeedback(IFeedbackHandler::eFT_OperationError, NULL); + SetTaskState(eTaskState_Error); + + m_localStats.MarkTaskAsNotRunning(); + + SetContinueFlag(false); + SetForceFlag(false); + + OnEndOperation(); + return 1; + } + + return 0; +} + +void CTask::OnBeginOperation() +{ + CTime tm=CTime::GetCurrentTime(); + + TString strFormat = _T("\r\n# COPYING THREAD STARTED #\r\nBegan processing data (dd:mm:yyyy) %day.%month.%year at %hour:%minute.%second"); + strFormat.Replace(_t("%year"), boost::lexical_cast(tm.GetYear()).c_str()); + strFormat.Replace(_t("%month"), boost::lexical_cast(tm.GetMonth()).c_str()); + strFormat.Replace(_t("%day"), boost::lexical_cast(tm.GetDay()).c_str()); + strFormat.Replace(_t("%hour"), boost::lexical_cast(tm.GetHour()).c_str()); + strFormat.Replace(_t("%minute"), boost::lexical_cast(tm.GetMinute()).c_str()); + strFormat.Replace(_t("%second"), boost::lexical_cast(tm.GetSecond()).c_str()); + m_log.logi(strFormat); +} + +void CTask::OnEndOperation() +{ + CTime tm=CTime::GetCurrentTime(); + + TString strFormat = _T("Finished processing data (dd:mm:yyyy) %day.%month.%year at %hour:%minute.%second"); + strFormat.Replace(_t("%year"), boost::lexical_cast(tm.GetYear()).c_str()); + strFormat.Replace(_t("%month"), boost::lexical_cast(tm.GetMonth()).c_str()); + strFormat.Replace(_t("%day"), boost::lexical_cast(tm.GetDay()).c_str()); + strFormat.Replace(_t("%hour"), boost::lexical_cast(tm.GetHour()).c_str()); + strFormat.Replace(_t("%minute"), boost::lexical_cast(tm.GetMinute()).c_str()); + strFormat.Replace(_t("%second"), boost::lexical_cast(tm.GetSecond()).c_str()); + m_log.logi(strFormat); +} + +void CTask::RequestStopThread() +{ + m_workerThread.SignalThreadToStop(); +} + +TSmartPath CTask::GetRelatedPath(EPathType ePathType) +{ + boost::shared_lock lock(m_lock); + + return GetRelatedPathNL(ePathType); +} + +TSmartPath CTask::GetRelatedPathNL(EPathType ePathType) +{ + BOOST_ASSERT(!m_strTaskDirectory.IsEmpty() || !m_strFilePath.IsEmpty()); + if(m_strTaskDirectory.IsEmpty() && m_strFilePath.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_MissingTaskSerializationPath); + + // in all cases we would like to have task definition path defined + TSmartPath strFilePath = m_strFilePath; + if(strFilePath.IsEmpty()) + strFilePath = m_strTaskDirectory + PathFromWString(m_tTaskDefinition.GetTaskUniqueID() + _T(".cht")); + + switch(ePathType) + { + case ePathType_TaskDefinition: + return strFilePath; + + case ePathType_TaskRarelyChangingState: + return strFilePath.AppendCopy(PathFromString(_T(".rstate")), false); + + case ePathType_TaskOftenChangingState: + return strFilePath.AppendCopy(PathFromString(_T(".ostate")), false); + + case ePathType_TaskLogFile: + return strFilePath.AppendCopy(PathFromString(_T(".log")), false); + + default: + THROW_CORE_EXCEPTION(eErr_UnhandledCase); + } +} + +void CTask::OnCfgOptionChanged(const TStringSet& rsetChanges, void* pParam) +{ + CTask* pTask = (CTask*)pParam; + if(!pTask) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + if(rsetChanges.HasValue(TaskPropData::GetPropertyName())) + { + pTask->m_workerThread.ChangePriority(GetTaskPropValue(pTask->GetTaskDefinition().GetConfiguration())); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// CTaskArray members +CTaskArray::CTaskArray() : + m_piFeedbackFactory(NULL), + m_stNextSessionUniqueID(NO_TASK_SESSION_UNIQUE_ID + 1) +{ +} + +CTaskArray::~CTaskArray() +{ + // NOTE: do not delete the feedback factory, since we are not responsible for releasing it +} + +void CTaskArray::Create(IFeedbackHandlerFactory* piFeedbackHandlerFactory) +{ + BOOST_ASSERT(piFeedbackHandlerFactory); + + m_piFeedbackFactory = piFeedbackHandlerFactory; +} + +CTaskPtr CTaskArray::CreateTask(const TTaskDefinition& tTaskDefinition) +{ + CTaskPtr spTask = CreateEmptyTask(); + if(spTask) + { + spTask->SetTaskDefinition(tTaskDefinition); + Add(spTask); + spTask->Store(); + } + + return spTask; +} + +CTaskPtr CTaskArray::ImportTask(const TSmartPath& strTaskPath) +{ + // load task definition from the new location + TTaskDefinition tTaskDefinition; + tTaskDefinition.Load(strTaskPath); + + return CreateTask(tTaskDefinition); +} + +CTaskPtr CTaskArray::CreateEmptyTask() +{ + BOOST_ASSERT(m_piFeedbackFactory); + if(!m_piFeedbackFactory) + return CTaskPtr(); + + IFeedbackHandler* piHandler = m_piFeedbackFactory->Create(); + if(!piHandler) + return CTaskPtr(); + + BOOST_ASSERT(m_stNextSessionUniqueID != NO_TASK_SESSION_UNIQUE_ID); + CTaskPtr spTask(new CTask(piHandler, m_stNextSessionUniqueID++)); + + // NO_TASK_SESSION_UNIQUE_ID is a special value so it should not be used to identify tasks + if(m_stNextSessionUniqueID == NO_TASK_SESSION_UNIQUE_ID) + ++m_stNextSessionUniqueID; + + return spTask; +} + +size_t CTaskArray::GetSize() const +{ + boost::shared_lock lock(m_lock); + return m_vTasks.size(); +} + +CTaskPtr CTaskArray::GetAt(size_t nIndex) const +{ + boost::shared_lock lock(m_lock); + + _ASSERTE(nIndex >= 0 && nIndex < m_vTasks.size()); + if(nIndex >= m_vTasks.size()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + return m_vTasks.at(nIndex); +} + +CTaskPtr CTaskArray::GetTaskBySessionUniqueID(size_t stSessionUniqueID) const +{ + if(stSessionUniqueID == NO_TASK_SESSION_UNIQUE_ID) + return CTaskPtr(); + + CTaskPtr spFoundTask; + + boost::shared_lock lock(m_lock); + BOOST_FOREACH(const CTaskPtr& spTask, m_vTasks) + { + if(spTask->GetSessionUniqueID() == stSessionUniqueID) + { + spFoundTask = spTask; + break; + } + } + + return spFoundTask; +} + +size_t CTaskArray::Add(const CTaskPtr& spNewTask) +{ + if(!spNewTask) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + boost::unique_lock lock(m_lock); + // here we know load succeeded + spNewTask->SetTaskDirectory(m_pathTasksDir); + + m_vTasks.push_back(spNewTask); + + spNewTask->OnRegisterTask(m_globalStats); + + return m_vTasks.size() - 1; +} + +void CTaskArray::RemoveAt(size_t stIndex, size_t stCount) +{ + boost::unique_lock lock(m_lock); + + _ASSERTE(stIndex >= m_vTasks.size() || stIndex + stCount > m_vTasks.size()); + if(stIndex >= m_vTasks.size() || stIndex + stCount > m_vTasks.size()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + for(std::vector::iterator iterTask = m_vTasks.begin() + stIndex; iterTask != m_vTasks.begin() + stIndex + stCount; ++iterTask) + { + CTaskPtr& spTask = *iterTask; + + // kill task if needed + spTask->KillThread(); + + spTask->OnUnregisterTask(); + } + + // remove elements from array + m_vTasks.erase(m_vTasks.begin() + stIndex, m_vTasks.begin() + stIndex + stCount); +} + +void CTaskArray::RemoveAll() +{ + boost::unique_lock lock(m_lock); + + StopAllTasksNL(); + + m_vTasks.clear(); +} + +void CTaskArray::RemoveAllFinished() +{ + std::vector vTasksToRemove; + + // separate scope for locking + { + boost::unique_lock lock(m_lock); + + size_t stIndex = m_vTasks.size(); + while(stIndex--) + { + CTaskPtr spTask = m_vTasks.at(stIndex); + + // delete only when the thread is finished + if((spTask->GetTaskState() == eTaskState_Finished || spTask->GetTaskState() == eTaskState_Cancelled)) + { + spTask->OnUnregisterTask(); + + vTasksToRemove.push_back(spTask); + m_vTasks.erase(m_vTasks.begin() + stIndex); + } + } + } + + BOOST_FOREACH(CTaskPtr& spTask, vTasksToRemove) + { + // delete associated files + spTask->DeleteProgress(); + } +} + +void CTaskArray::RemoveFinished(const CTaskPtr& spSelTask) +{ + boost::unique_lock lock(m_lock); + + // this might be optimized by copying tasks to a local table in critical section, and then deleting progress files outside of the critical section + for(std::vector::iterator iterTask = m_vTasks.begin(); iterTask != m_vTasks.end(); ++iterTask) + { + CTaskPtr& spTask = *iterTask; + + if(spTask == spSelTask && (spTask->GetTaskState() == eTaskState_Finished || spTask->GetTaskState() == eTaskState_Cancelled)) + { + // kill task if needed + spTask->KillThread(); + + spTask->OnUnregisterTask(); + + // delete associated files + spTask->DeleteProgress(); + + m_vTasks.erase(iterTask); + + return; + } + } +} + +void CTaskArray::StopAllTasks() +{ + boost::unique_lock lock(m_lock); + + StopAllTasksNL(); +} + +void CTaskArray::ResumeWaitingTasks(size_t stMaxRunningTasks) +{ + boost::unique_lock lock(m_lock); + + if(stMaxRunningTasks == 0 || m_globalStats.GetRunningTasksCount() < stMaxRunningTasks) + { + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + // turn on some thread - find something with wait state + if(spTask->GetTaskState() == eTaskState_Waiting && (stMaxRunningTasks == 0 || m_globalStats.GetRunningTasksCount() < stMaxRunningTasks)) + { + spTask->m_localStats.MarkTaskAsRunning(); + spTask->SetContinueFlagNL(true); + } + } + } +} + +void CTaskArray::SaveData() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->Store(); + } +} + +void CTaskArray::LoadDataProgress() +{ + if(m_pathTasksDir.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_MissingTaskSerializationPath); + + CTaskPtr spTask; + TSmartPath pathFound; + WIN32_FIND_DATA wfd; + bool bExceptionEncountered = false; + + const size_t stMaxMsgSize = 4096; + boost::shared_array spMsgBuffer(new wchar_t[stMaxMsgSize]); + spMsgBuffer[0] = _T('\0'); + + // find all CH Task files + TSmartPath pathToFind = m_pathTasksDir + PathFromString(_T("*.cht")); + + HANDLE hFind = ::FindFirstFile(pathToFind.ToString(), &wfd); + BOOL bContinue = TRUE; + while(hFind != INVALID_HANDLE_VALUE && bContinue) + { + pathFound = m_pathTasksDir + PathFromString(wfd.cFileName); + // load data + spTask = CreateEmptyTask(); + try + { + spTask->Load(pathFound); + + // add read task to array + Add(spTask); + } + catch(icpf::exception& e) + { + e.get_info(spMsgBuffer.get(), stMaxMsgSize); + bExceptionEncountered = true; + } + catch(std::exception& e) + { + _tcsncpy_s(spMsgBuffer.get(), stMaxMsgSize, CA2CT(e.what()), _TRUNCATE); + bExceptionEncountered = true; + } + + if(bExceptionEncountered) + { + TString strFmt = _T("Cannot load task data: %path (reason: %reason)"); + strFmt.Replace(_T("%path"), pathFound.ToString()); + strFmt.Replace(_T("%reason"), spMsgBuffer.get()); + + LOG_ERROR(strFmt); + + bExceptionEncountered = false; + } + bContinue = ::FindNextFile(hFind, &wfd); + } + + ::FindClose(hFind); +} + +void CTaskArray::TasksBeginProcessing() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->BeginProcessing(); + } +} + +void CTaskArray::TasksPauseProcessing() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->PauseProcessing(); + } +} + +void CTaskArray::TasksResumeProcessing() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->ResumeProcessing(); + } +} + +void CTaskArray::TasksRestartProcessing() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->RestartProcessing(); + } +} + +bool CTaskArray::TasksRetryProcessing() +{ + boost::shared_lock lock(m_lock); + bool bChanged=false; + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + if(spTask->RetryProcessing()) + bChanged = true; + } + + return bChanged; +} + +void CTaskArray::TasksCancelProcessing() +{ + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->CancelProcessing(); + } +} + +ull_t CTaskArray::GetPosition() +{ + return m_globalStats.GetGlobalProcessedSize(); +} + +ull_t CTaskArray::GetRange() +{ + return m_globalStats.GetGlobalTotalSize(); +} + +int CTaskArray::GetPercent() +{ + return m_globalStats.GetProgressPercents(); +} + +bool CTaskArray::AreAllFinished() +{ + bool bFlag=true; + + if(m_globalStats.GetRunningTasksCount() != 0) + bFlag = false; + else + { + boost::shared_lock lock(m_lock); + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + ETaskCurrentState eState = spTask->GetTaskState(); + bFlag = (eState == eTaskState_Finished || eState == eTaskState_Cancelled || eState == eTaskState_Paused || eState == eTaskState_Error); + + if(!bFlag) + break; + } + } + + return bFlag; +} + +void CTaskArray::SetTasksDir(const TSmartPath& pathDir) +{ + boost::unique_lock lock(m_lock); + m_pathTasksDir = pathDir; +} + +void CTaskArray::StopAllTasksNL() +{ + // kill all unfinished tasks - send kill request + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->RequestStopThread(); + } + + // wait for finishing + BOOST_FOREACH(CTaskPtr& spTask, m_vTasks) + { + spTask->KillThread(); + } +} + +END_CHCORE_NAMESPACE Index: src/libchcore/task.h =================================================================== diff -u --- src/libchcore/task.h (revision 0) +++ src/libchcore/task.h (revision 0cf74c78280b58c363868caafb9bf493a57aa006) @@ -0,0 +1,340 @@ +/*************************************************************************** +* Copyright (C) 2001-2008 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. * +***************************************************************************/ +#ifndef __TASK_H__ +#define __TASK_H__ + +#include "libchcore.h" +#include "TAutoHandles.h" +#include "TWorkerThreadController.h" +#include "FileInfo.h" +#include "DataBuffer.h" +#include "FeedbackHandlerBase.h" +#include "FileFilter.h" +#include "TTaskDefinition.h" +#include "TTaskConfigTracker.h" +#include "TBasePathData.h" +#include "TSubTaskBase.h" +#include "TTaskLocalStats.h" +#include "TTaskGlobalStats.h" +#include "TBasicProgressInfo.h" +#include "TLocalFilesystem.h" +#include "..\libicpf\log.h" + +BEGIN_CHCORE_NAMESPACE + +// enum representing current processing state of the task +enum ETaskCurrentState +{ + eTaskState_None, + eTaskState_Waiting, + eTaskState_Processing, + eTaskState_Paused, + eTaskState_Cancelled, + eTaskState_Error, + eTaskState_Finished, + + // insert new values before this one + eTaskState_Max +}; + +// special value representing no task +#define NO_TASK_SESSION_UNIQUE_ID 0 + +// structure for getting status of a task +struct TASK_DISPLAY_DATA +{ + TString m_strFullFilePath; + TString m_strFileName; + + int m_iCurrentBufferSize; + int m_iCurrentBufferIndex; + size_t m_stIndex; + size_t m_stSize; + + TSmartPath m_pathDstPath; + TFiltersArray* m_pafFilters; + + ETaskCurrentState m_eTaskState; + EOperationType m_eOperationType; + ESubOperationType m_eSubOperationType; + + int m_nPriority; + + ull_t m_ullProcessedSize; + ull_t m_ullSizeAll; + int m_nPercent; + + time_t m_timeElapsed; + + TString m_strUniqueName; // doesn't change from first setting + + bool m_bIgnoreDirectories; + bool m_bCreateEmptyFiles; +}; + +struct TASK_MINI_DISPLAY_DATA +{ + TString m_strPath; + + ETaskCurrentState m_eTaskState; + + int m_nPercent; +}; + +/////////////////////////////////////////////////////////////////////////// +// CTask + +class LIBCHCORE_API CTask +{ +public: + enum EPathType + { + ePathType_TaskDefinition, + ePathType_TaskRarelyChangingState, + ePathType_TaskOftenChangingState, + ePathType_TaskLogFile, + }; + +public: + ~CTask(); + + const TTaskDefinition& GetTaskDefinition() const { return m_tTaskDefinition; } + + void SetTaskState(ETaskCurrentState eTaskState); + ETaskCurrentState GetTaskState() const; + + // m_nBufferSize + void SetBufferSizes(const TBufferSizes& bsSizes); + void GetBufferSizes(TBufferSizes& bsSizes); + int GetCurrentBufferIndex(); + + // thread + void SetPriority(int nPriority); + + void Load(const TSmartPath& strPath); + void Store(); + + void BeginProcessing(); + + void PauseProcessing(); // pause + void ResumeProcessing(); // resume + bool RetryProcessing(); // retry + void RestartProcessing(); // from beginning + void CancelProcessing(); // cancel + + void GetSnapshot(TASK_DISPLAY_DATA *pData); + void GetMiniSnapshot(TASK_MINI_DISPLAY_DATA *pData); + + void SetTaskDirectory(const TSmartPath& strDir); + TSmartPath GetTaskDirectory() const; + + void SetTaskFilePath(const TSmartPath& strPath); + TSmartPath GetTaskFilePath() const; + + void SetForceFlag(bool bFlag = true); + bool GetForceFlag(); + + size_t GetSessionUniqueID() const { return m_stSessionUniqueID; } + + TSmartPath GetRelatedPath(EPathType ePathType); + +protected: + CTask(IFeedbackHandler* piFeedbackHandler, size_t stSessionUniqueID); + + void SetTaskDefinition(const TTaskDefinition& rTaskDefinition); + + // 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 + void OnRegisterTask(TTasksGlobalStats& rtGlobalStats); + /// Method is called when task is being removed from the CTaskArray object + void OnUnregisterTask(); + + /// Method is called when processing is being started + void OnBeginOperation(); + /// Method is called when processing is being ended + void OnEndOperation(); + + // Processing operations + + /// Thread function that delegates call to the CTask::ThrdProc + static DWORD WINAPI DelegateThreadProc(LPVOID pParam); + + /// Main function for the task processing thread + DWORD WINAPI ThrdProc(); + + TSubTaskBase::ESubOperationResult CheckForWaitState(); + + // m_nStatus + void SetStatusNL(UINT nStatus, UINT nMask); + UINT GetStatusNL(UINT nMask = 0xffffffff); + + void CalculateProcessedSize(); + void CalculateProcessedSizeNL(); + + void CalculateTotalSizeNL(); + + void DeleteProgress(); + + void SetForceFlagNL(bool bFlag = true); + bool GetForceFlagNL(); + + void SetContinueFlag(bool bFlag = true); + bool GetContinueFlag(); + void SetContinueFlagNL(bool bFlag = true); + bool GetContinueFlagNL(); + + bool CanBegin(); + + void KillThread(); + void RequestStopThread(); + + TSmartPath GetRelatedPathNL(EPathType ePathType); + + static void OnCfgOptionChanged(const TStringSet& rsetChanges, void* pParam); + +private: + // task initial information (needed to start a task); might be a bit processed. + TTaskDefinition m_tTaskDefinition; + + TTaskConfigTracker m_cfgTracker; + + TBasePathDataContainer m_arrSourcePathsInfo; + + // current task state (derivatives of the task initial information) + // changing slowly or only partially + TFileInfoArray m_files; // list of files/directories found during operating on the task input data (filled by search for files) + + // changing fast + volatile ETaskCurrentState m_eCurrentState; // current state of processing this task represents + + TTaskBasicProgressInfo m_tTaskBasicProgressInfo; // task progress information + + // task control variables (per-session state) + TTaskLocalStats m_localStats; // local statistics + + // task settings + TFiltersArray m_afFilters; // filtering settings for files (will be filtered according to the rules inside when searching for files) + + bool m_bForce; // if the continuation of tasks should be independent of max concurrently running task limit + bool m_bContinue; // allows task to continue + + TSmartPath m_strTaskDirectory; // base path at which the files will be stored + TSmartPath 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 + icpf::log_file m_log; ///< Log file where task information will be stored + + // Local filesystem access + TLocalFilesystem m_fsLocal; + + /// Thread controlling object + TWorkerThreadController m_workerThread; + + /// Mutex for locking concurrent access to members of this class +#pragma warning(push) +#pragma warning(disable: 4251) + mutable boost::shared_mutex m_lock; +#pragma warning(pop) + + /// Pointer to the feedback handler, providing responses to feedback requests + IFeedbackHandler* m_piFeedbackHandler; + + friend class CTaskArray; +}; + +typedef boost::shared_ptr CTaskPtr; + +/////////////////////////////////////////////////////////////////////////// +// CTaskArray + +class LIBCHCORE_API CTaskArray +{ +public: + CTaskArray(); + ~CTaskArray(); + + void Create(IFeedbackHandlerFactory* piFeedbackHandlerFactory); + + CTaskPtr CreateTask(const TTaskDefinition& tTaskDefinition); + CTaskPtr ImportTask(const TSmartPath& strTaskPath); + + size_t GetSize() const; + + CTaskPtr GetAt(size_t stIndex) const; + CTaskPtr GetTaskBySessionUniqueID(size_t stSessionUniqueID) const; + + size_t Add(const CTaskPtr& spNewTask); + + void RemoveAt(size_t stIndex, size_t stCount = 1); + void RemoveAll(); + void RemoveAllFinished(); + void RemoveFinished(const CTaskPtr& spSelTask); + + void ResumeWaitingTasks(size_t stMaxRunningTasks); + void StopAllTasks(); + + void SaveData(); + void LoadDataProgress(); + + void TasksBeginProcessing(); + void TasksPauseProcessing(); + void TasksResumeProcessing(); + void TasksRestartProcessing(); + bool TasksRetryProcessing(); + void TasksCancelProcessing(); + + ull_t GetPosition(); + ull_t GetRange(); + int GetPercent(); + + bool AreAllFinished(); + + void SetTasksDir(const TSmartPath& pathDir); + +protected: + void StopAllTasksNL(); + + CTaskPtr CreateEmptyTask(); + +public: + TSmartPath m_pathTasksDir; + +private: +#pragma warning(push) +#pragma warning(disable: 4251) + mutable boost::shared_mutex m_lock; + std::vector m_vTasks; // vector with tasks objects +#pragma warning(pop) + + TTasksGlobalStats m_globalStats; // global stats for all tasks + + size_t m_stNextSessionUniqueID; // global counter for providing unique ids for tasks per session (launch of the program) + +protected: + IFeedbackHandlerFactory* m_piFeedbackFactory; +}; + +END_CHCORE_NAMESPACE + +#endif