todoctrldata.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 3,041 行 · 第 1/5 页
CPP
3,041 行
// ToDoCtrlData.cpp: implementation of the CToDoCtrlData class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ToDoCtrlData.h"
#include "..\shared\xmlfile.h"
#include "..\shared\timehelper.h"
#include "..\shared\datehelper.h"
#include "..\shared\misc.h"
#include "..\shared\enstring.h"
#include "..\shared\treectrlhelper.h"
#include <float.h>
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
IMPLEMENT_FIXED_ALLOC(TODOITEM, 1024);
TODOITEM::TODOITEM(LPCTSTR szTitle, LPCTSTR szComments) :
sTitle(szTitle),
sComments(szComments),
color(0),
nPriority(5),
nRisk(0),
nPercentDone(0),
dTimeEstimate(0),
dTimeSpent(0),
nTimeEstUnits(TDITU_HOURS),
nTimeSpentUnits(TDITU_HOURS),
dCost(0),
bFlagged(FALSE),
dateCreated(COleDateTime::GetCurrentTime())
{
SetModified();
ResetCalcs();
}
TODOITEM::TODOITEM() :
color(0),
nPriority(5),
nRisk(0),
nPercentDone(0),
dTimeEstimate(0),
dTimeSpent(0),
nTimeEstUnits(TDITU_HOURS),
nTimeSpentUnits(TDITU_HOURS),
dCost(0),
bFlagged(FALSE),
dateCreated(COleDateTime::GetCurrentTime())
{
SetModified();
ResetCalcs();
}
TODOITEM::TODOITEM(const TODOITEM& tdi) :
sTitle(tdi.sTitle),
sComments(tdi.sComments),
color(tdi.color),
sFileRefPath(tdi.sFileRefPath),
sAllocBy(tdi.sAllocBy),
sStatus(tdi.sStatus),
nPriority(tdi.nPriority),
nPercentDone(tdi.nPercentDone),
dTimeEstimate(tdi.dTimeEstimate),
dTimeSpent(tdi.dTimeSpent),
nTimeEstUnits(tdi.nTimeEstUnits),
nTimeSpentUnits(tdi.nTimeSpentUnits),
dCost(tdi.dCost),
dateStart(tdi.dateStart),
dateDue(tdi.dateDue),
dateDone(tdi.dateDone),
dateCreated(tdi.dateCreated),
bFlagged(tdi.bFlagged),
sCreatedBy(tdi.sCreatedBy),
nRisk(tdi.nRisk),
sExternalID(tdi.sExternalID),
trRecurrence(tdi.trRecurrence),
sCommentsTypeID(tdi.sCommentsTypeID)
{
if (dateCreated.m_dt == 0.0)
dateCreated = COleDateTime::GetCurrentTime();
aCategories.Copy(tdi.aCategories);
aAllocTo.Copy(tdi.aAllocTo);
SetModified();
ResetCalcs();
}
BOOL TODOITEM::HasCreation() const
{
return (dateCreated.m_dt > 0) ? TRUE : FALSE;
}
BOOL TODOITEM::HasLastMod() const
{
return (tLastMod.m_dt > 0) ? TRUE : FALSE;
}
BOOL TODOITEM::HasStart() const
{
return (dateStart.m_dt > 0) ? TRUE : FALSE;
}
BOOL TODOITEM::HasDue() const
{
return (dateDue.m_dt > 0) ? TRUE : FALSE;
}
BOOL TODOITEM::IsDone() const
{
return (dateDone.m_dt > 0) ? TRUE : FALSE;
}
void TODOITEM::ClearStart()
{
dateStart.m_dt = 0;
}
void TODOITEM::ClearDue()
{
dateDue.m_dt = 0;
}
void TODOITEM::ClearDone()
{
dateDone.m_dt = 0;
}
BOOL TODOITEM::IsDue() const
{
return IsDue(COleDateTime::GetCurrentTime());
}
BOOL TODOITEM::IsDue(const COleDateTime& dateDueBy) const
{
if (IsDone() || !HasDue())
return FALSE;
return (floor(dateDue.m_dt) <= floor(dateDueBy.m_dt));
}
void TODOITEM::SetModified()
{
tLastMod = COleDateTime::GetCurrentTime();
}
void TODOITEM::ResetCalcs() const
{
nCalcPriority = nCalcPriorityIncDue = nCalcPercent = nCalcRisk = -1;
dCalcTimeEstimate = dCalcTimeSpent = dCalcCost = -1;
dateEarliestDue.m_dt = -1;
bGoodAsDone = bDue = -1;
nSubtasksCount = nSubtasksDone = -1;
}
CString TODOITEM::GetFirstCategory() const
{
return aCategories.GetSize() ? aCategories[0] : "";
}
CString TODOITEM::GetFirstAllocTo() const
{
return aAllocTo.GetSize() ? aAllocTo[0] : "";
}
BOOL TODOITEM::GetNextOccurence(COleDateTime& dtNext) const
{
if (trRecurrence.bRecalcFromDue)
return trRecurrence.GetNextOccurence(dateDue, dtNext);
// else
return trRecurrence.GetNextOccurence(COleDateTime::GetCurrentTime(), dtNext);
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CToDoCtrlData::CToDoCtrlData(CTreeCtrl& tree, const CWordArray& aStyles) :
m_tree(tree), m_aStyles(aStyles), m_bSortDueTodayHigh(-1)
{
}
CToDoCtrlData::~CToDoCtrlData()
{
DeleteAllTasks();
}
TODOITEM* CToDoCtrlData::NewTask(const TODOITEM* pTDIRef)
{
if (pTDIRef)
return new TODOITEM(*pTDIRef);
else
return new TODOITEM;
}
TODOITEM* CToDoCtrlData::GetTask(DWORD dwID) const
{
TODOITEM* pTDI;
return (dwID && m_mapTDItems.Lookup(dwID, pTDI)) ? pTDI : NULL;
}
TODOITEM* CToDoCtrlData::GetTask(HTREEITEM hti) const
{
return GetTask(GetTaskID(hti));
}
void CToDoCtrlData::AddTask(DWORD dwID, TODOITEM* pTDI)
{
if (dwID && pTDI)
{
// must delete duplicates else we'll get a memory leak
TODOITEM* pExist = GetTask(dwID);
if (pExist)
{
m_mapTDItems.RemoveKey(dwID);
delete pExist;
}
}
m_mapTDItems.SetAt(dwID, pTDI);
}
void CToDoCtrlData::DeleteTask(DWORD dwID)
{
ASSERT (dwID && GetTask(dwID));
delete GetTask(dwID);
m_mapTDItems.RemoveKey(dwID);
}
void CToDoCtrlData::DeleteAllTasks(BOOL bIncTree)
{
POSITION pos = m_mapTDItems.GetStartPosition();
TODOITEM* pTDI;
DWORD dwID;
while (pos)
{
m_mapTDItems.GetNextAssoc(pos, dwID, pTDI);
delete pTDI;
}
m_mapTDItems.RemoveAll();
if (bIncTree && m_tree.GetSafeHwnd())
{
m_tree.SelectItem(NULL);
m_tree.DeleteAllItems();
}
}
int CToDoCtrlData::FindTasks(const SEARCHPARAMS& params, CResultArray& aResults) const
{
if (!GetTaskCount())
return 0;
HTREEITEM hti = m_tree.GetChildItem(NULL);
while (hti)
{
FindTasks(hti, params, aResults);
hti = m_tree.GetNextItem(hti, TVGN_NEXT);
}
// else
return aResults.GetSize();
}
int CToDoCtrlData::FindTasks(HTREEITEM hti, const SEARCHPARAMS& params, CResultArray& aResults) const
{
SEARCHRESULT result;
if (TaskMatches(hti, params, result))
aResults.Add(result);
// also check children and their children recursively
HTREEITEM htiChild = m_tree.GetChildItem(hti);
while (htiChild)
{
FindTasks(htiChild, params, aResults);
// next
htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
}
return aResults.GetSize();
}
DWORD CToDoCtrlData::FindFirstTask(const SEARCHPARAMS& params, SEARCHRESULT& result) const
{
if (!GetTaskCount())
return 0;
HTREEITEM hti = m_tree.GetChildItem(NULL);
DWORD dwTaskID = 0;
while (hti && !dwTaskID)
{
dwTaskID = FindFirstTask(hti, params, result);
hti = m_tree.GetNextItem(hti, TVGN_NEXT);
}
// else
return dwTaskID;
}
DWORD CToDoCtrlData::FindFirstTask(HTREEITEM hti, const SEARCHPARAMS& params, SEARCHRESULT& result) const
{
if (TaskMatches(hti, params, result))
return result.dwID;
// also check children and their children recursively
HTREEITEM htiChild = m_tree.GetChildItem(hti);
DWORD dwTaskID = 0;
while (htiChild && !dwTaskID)
{
dwTaskID = FindFirstTask(htiChild, params, result);
htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
}
return dwTaskID;
}
BOOL CToDoCtrlData::TaskMatches(DWORD dwID, const SEARCHPARAMS& params, SEARCHRESULT& result) const
{
HTREEITEM hti = CTreeCtrlHelper(m_tree).FindItem(dwID, NULL);
return TaskMatches(hti, params, result);
}
BOOL CToDoCtrlData::TaskMatches(HTREEITEM hti, const SEARCHPARAMS& params, SEARCHRESULT& result) const
{
TODOITEM* pTDI = GetTask(hti);
if (!pTDI)
return 0;
BOOL bMatch = FALSE;
DWORD dwID = m_tree.GetItemData(hti);
BOOL bIncDone = (params.dwFlags & FIND_INCLUDEDONE);
BOOL bIsDone = IsTaskDone(hti, TDCCHECKALL);
if (params.nFindWhat == FIND_DONEDATE)
{
if (pTDI->IsDone())
bMatch = TaskMatches(pTDI->dateDone, params, result);
}
else if (bIncDone || !bIsDone)
{
switch (params.nFindWhat)
{
case FIND_TITLECOMMENTS:
bMatch = (TaskMatches(pTDI->sTitle, params, result) || TaskMatches(pTDI->sComments, params, result));
break;
case FIND_ALLOCTO:
bMatch = TaskMatches(pTDI->aAllocTo, params, result);
break;
case FIND_ALLOCBY:
bMatch = TaskMatches(pTDI->sAllocBy, params, result);
break;
case FIND_CREATEDBY:
bMatch = TaskMatches(pTDI->sCreatedBy, params, result);
break;
case FIND_STATUS:
bMatch = TaskMatches(pTDI->sStatus, params, result);
break;
case FIND_CATEGORY:
bMatch = TaskMatches(pTDI->aCategories, params, result);
break;
case FIND_EXTERNALID:
bMatch = TaskMatches(pTDI->sExternalID, params, result);
break;
case FIND_CREATIONDATE:
if (pTDI->HasCreation())
bMatch = TaskMatches(pTDI->dateCreated, params, result);
break;
case FIND_STARTDATE:
if (pTDI->HasStart())
bMatch = TaskMatches(pTDI->dateStart, params, result);
break;
case FIND_DUEDATE:
if (pTDI->HasDue())
bMatch = TaskMatches(pTDI->dateDue, params, result);
break;
case FIND_LASTMOD:
if (pTDI->HasLastMod())
bMatch = TaskMatches(pTDI->tLastMod, params, result);
break;
case FIND_PRIORITY:
bMatch = TaskMatches(pTDI->nPriority, params, result);
break;
case FIND_RISK:
bMatch = TaskMatches(pTDI->nRisk, params, result);
break;
case FIND_TASKID:
bMatch = TaskMatches((int)dwID, params, result);
break;
case FIND_PERCENTDONE:
bMatch = TaskMatches(pTDI->nPercentDone, params, result);
break;
case FIND_TIMEEST:
bMatch = TaskMatches(pTDI->dTimeEstimate, params, result);
break;
case FIND_TIMESPENT:
bMatch = TaskMatches(pTDI->dTimeSpent, params, result);
break;
case FIND_COST:
bMatch = TaskMatches(pTDI->dCost, params, result);
break;
case FIND_FLAG:
bMatch = pTDI->bFlagged;
break;
case FIND_VERSION:
bMatch = TaskMatches(pTDI->sVersion, params, result);
break;
}
}
if (bMatch)
{
result.bDone = bIsDone;
result.dwID = dwID;
result.hti = hti;
}
return bMatch;
}
BOOL CToDoCtrlData::TaskMatches(const COleDateTime& date, const SEARCHPARAMS& params, SEARCHRESULT& result)
{
if (floor(date.m_dt) >= floor(params.dateFrom.m_dt) &&
floor(date.m_dt) <= floor(params.dateTo.m_dt))
{
result.dateMatch = date;
return TRUE;
}
// else
return FALSE;
}
BOOL CToDoCtrlData::TaskMatches(const CString& sText, const SEARCHPARAMS& params, SEARCHRESULT& result)
{
CStringArray aWords;
if (!Misc::ParseSearchString(params.sText, aWords))
return FALSE;
BOOL bMatchCase = (params.dwFlags & FIND_MATCHCASE);
BOOL bMatchWholeWord = (params.dwFlags & FIND_MATCHWHOLEWORD);
// cycle all the words
for (int nWord = 0; nWord < aWords.GetSize(); nWord++)
{
CString sWord = aWords.GetAt(nWord);
if (Misc::FindWord(sWord, sText, bMatchCase, bMatchWholeWord))
{
result.sMatch = sText;
return TRUE;
}
}
return FALSE;
}
BOOL CToDoCtrlData::TaskMatches(const CStringArray& aItems, const SEARCHPARAMS& params, SEARCHRESULT& result)
{
BOOL bMatch = FALSE;
if (params.dwFlags & FIND_MATCHALLARRAY)
bMatch = Misc::ArraysMatch(aItems, params.aItems);
else
{
if (aItems.GetSize())
bMatch = Misc::MatchAny(aItems, params.aItems);
else
// special case: task has no item and param.aItems
// contains an empty item
bMatch = (Misc::Find(params.aItems, "") != -1);
}
if (bMatch)
result.sMatch = Misc::FormatArray(aItems);
return bMatch;
}
BOOL CToDoCtrlData::TaskMatches(double dValue, const SEARCHPARAMS& params, SEARCHRESULT& result)
{
if (dValue >= params.dFrom && dValue <= params.dTo)
{
result.dMatch = dValue;
return TRUE;
}
// else
return FALSE;
}
BOOL CToDoCtrlData::TaskMatches(int nValue, const SEARCHPARAMS& params, SEARCHRESULT& result)
{
if (nValue >= params.nFrom && nValue <= params.nTo)
{
result.nMatch = nValue;
return TRUE;
}
// else
return FALSE;
}
CString CToDoCtrlData::GetTaskTitle(DWORD dwID) const
{
TODOITEM* pTDI = GetTask(dwID);
if (pTDI)
return pTDI->sTitle;
return "";
}
CString CToDoCtrlData::GetTaskComments(DWORD dwID) const
{
TODOITEM* pTDI = GetTask(dwID);
if (pTDI)
return pTDI->sComments;
return "";
}
CString CToDoCtrlData::GetTaskCustomComments(DWORD dwID, CString& sCommentsTypeID) const
{
TODOITEM* pTDI = GetTask(dwID);
if (pTDI)
{
sCommentsTypeID = pTDI->sCommentsTypeID;
return pTDI->sCustomComments;
}
// else
sCommentsTypeID.Empty();
return "";
}
double CToDoCtrlData::GetTaskCost(DWORD dwID) const
{
TODOITEM* pTDI = GetTask(dwID);
if (pTDI)
return pTDI->dCost;
return 0;
}
double CToDoCtrlData::GetTaskTimeEstimate(DWORD dwID, int& nUnits) const
{
TODOITEM* pTDI = GetTask(dwID);
if (pTDI)
{
nUnits = pTDI->nTimeEstUnits;
return pTDI->dTimeEstimate;
}
return 0;
}
double CToDoCtrlData::GetTaskTimeSpent(DWORD dwID, int& nUnits) const
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?