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 + -
显示快捷键?