filteredtodoctrl.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 723 行 · 第 1/2 页
CPP
723 行
// FilteredToDoCtrl.cpp: implementation of the CFilteredToDoCtrl class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FilteredToDoCtrl.h"
#include "resource.h"
#include "..\shared\holdredraw.h"
#include "..\shared\datehelper.h"
#include "..\shared\enstring.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFilteredToDoCtrl::CFilteredToDoCtrl(CContentMgr& mgr, const CONTENTFORMAT& cfDefault) :
CToDoCtrl(mgr, cfDefault), m_nHiddenCount(0)
{
}
CFilteredToDoCtrl::~CFilteredToDoCtrl()
{
}
int CFilteredToDoCtrl::GetAllTasks(CTaskFile& tasks) const
{
if (!m_nHiddenCount) // nothing to merge in
return CToDoCtrl::GetAllTasks(tasks);
// else merge back in any tasks that were previously removed
// to make sure that changes to the visible tasks (esp structure)
// are not overwritten by the hidden tasks we need to merge
// from the visible tasks -> hidden tasks.
CTaskFile tasksSrc;
if (CToDoCtrl::GetAllTasks(tasksSrc))
{
tasks.Copy(m_tasksHidden);
tasks.Merge(tasksSrc, TRUE, TRUE);
}
else // nothing showing so just copy hidden
tasks.Copy(m_tasksHidden);
return tasks.GetTaskCount();
}
HTREEITEM CFilteredToDoCtrl::SetAllTasks(const CTaskFile& tasks)
{
HTREEITEM hti = NULL;
if (HasFilter())
{
int nTaskCount = tasks.GetTaskCount();
// this will contain the visible
CTaskFile tasksShow;
tasksShow.Copy(tasks);
// this will contain the non-visible tasks. ie mutually exclusive
m_tasksHidden.Copy(tasks);
FilterTasks(m_tasksHidden, NULL, tasksShow, NULL);
// work out how many are hidden
m_nHiddenCount = nTaskCount - tasksShow.GetTaskCount();
TRACE ("CFilteredToDoCtrl::SetAllTasks(%d showing, %d hidden)\n",
tasksShow.GetTaskCount(), m_tasksHidden.GetTaskCount());
m_mgrPrompts.SetPrompt(m_tree, CEnString(IDS_TDC_FILTEREDTASKLISTPROMPT), TVM_GETCOUNT);
hti = CToDoCtrl::SetAllTasks(tasksShow);
}
else
{
m_mgrPrompts.SetPrompt(m_tree, CEnString(IDS_TDC_TASKLISTPROMPT), TVM_GETCOUNT);
m_tasksHidden.Reset();
m_nHiddenCount = 0;
hti = CToDoCtrl::SetAllTasks(tasks);
}
m_tree.Invalidate();
return hti;
}
FILTER_TYPE CFilteredToDoCtrl::GetFilter(FTDCFILTER& filter) const
{
filter = m_filter;
return m_filter.nFilter;
}
void CFilteredToDoCtrl::SetFilter(const FTDCFILTER& filter)
{
if (m_filter == filter)
return; // no change
m_filter = filter;
RefreshFilter();
}
void CFilteredToDoCtrl::ClearFilter()
{
if (HasFilter())
{
FTDCFILTER filter; // empty filter
SetFilter(filter);
}
}
UINT CFilteredToDoCtrl::GetTaskCount(UINT* pVisible) const
{
int nVisible = CToDoCtrl::GetTaskCount();
if (pVisible)
*pVisible = nVisible;
return (nVisible + m_nHiddenCount);
}
void CFilteredToDoCtrl::RefreshFilter()
{
CHoldRedraw hr(m_tree);
CWaitCursor cursor;
CTaskFile tasks;
if (GetAllTasks(tasks))
{
// save and restore focus
HWND hwndFocus = ::GetFocus();
if (CToDoCtrl::GetTaskCount())
SaveExpandedState();
InitDueDate();
HTREEITEM htiFirst = SetAllTasks(tasks);
m_data.ResetCachedCalculations();
// restore last expanded state
HTREEITEM htiSel = LoadExpandedState(FALSE);
if (!htiSel)
htiSel = htiFirst;
if (htiSel)
{
SelectItem(htiSel);
m_tree.EnsureVisible(htiSel);
}
if (hwndFocus != ::GetFocus())
::SetFocus(hwndFocus);
// redo last sort
if (GetSortBy() != TDC_SORTDISABLED)
{
m_bModSinceLastSort = TRUE; // so the sort won't switch directions
Sort(GetSortBy());
}
}
}
void CFilteredToDoCtrl::FilterTasks(CTaskFile& tasksHide, HTASKITEM htHide,
CTaskFile& tasksShow, HTASKITEM htShow)
{
// iterate both lists at the same time
HTASKITEM htchildHide = tasksHide.GetFirstTask(htHide);
HTASKITEM htchildShow = tasksShow.GetFirstTask(htShow);
while (htchildHide)
{
ASSERT (htchildShow);
DWORD dwID = tasksShow.GetTaskID(htchildShow);
// Note: because we will be hiding tasks from the underlying CToDoCtrl
// we become responsible for validating m_dwNextUniqueID against the
// actual IDs of the tasks
m_dwNextUniqueID = max(m_dwNextUniqueID, dwID + 1);
// save in case we later need to delete
HTASKITEM htCacheHide = htchildHide;
HTASKITEM htCacheShow = htchildShow;
// if it has children then leave it in place but process children
BOOL bHasChildren = (tasksShow.GetFirstTask(htchildShow) != NULL);
// get next first in case we delete
htchildHide = tasksHide.GetNextTask(htchildHide);
htchildShow = tasksShow.GetNextTask(htchildShow);
if (bHasChildren)
{
// we need to handle done tasks in a special way if we have
// the TDCS_TREATSUBCOMPLETEDASDONE style set because trying
// to figure out whether to delete the parent after all the
// children have been deleted is too tricky. so if we're only
// interested in incomplete tasks and we are sure that this
// task is complete then we can deal with it right away
if (m_filter.nFilter == FT_NOTDONE && HasStyle(TDCS_TREATSUBCOMPLETEDASDONE) &&
IsTaskDone(tasksShow, htCacheShow))
{
tasksShow.DeleteTask(htCacheShow);
}
else // we go through all the tests
{
FilterTasks(tasksHide, htCacheHide, tasksShow, htCacheShow);
// if the task previouly had children but now they've all
// be filtered out, decide whether the parent task needs to be
// deleted too
BOOL bDelete = FALSE;
if (bHasChildren && !tasksShow.GetFirstTask(htCacheShow))
{
bDelete = (MatchFilter(tasksShow, htCacheShow) != FTDC_MATCH);
}
if (bDelete)
tasksShow.DeleteTask(htCacheShow);
else
{
// task will exist in both lists so clear attributes from hidden
// task to ensure that attributes are correctly merged back
// in from shown item (which may have been edited).
// BUT make sure we don't delete the ID else the merge
// will go horribly wrong
tasksHide.DeleteTaskAttributes(htCacheHide);
tasksHide.SetTaskID(htCacheHide, dwID);
}
}
}
else // has no children so check for removal
{
// if the current item matches the filter then we delete
// it from the 'hide' tasks because we will be showing
// it, else we delete from the 'show' tasks because we
// will be hiding it
FTMATCHRESULT nMatch = MatchFilter(tasksHide, htCacheHide);
if (nMatch == FTDC_MATCH)
tasksHide.DeleteTask(htCacheHide);
else
tasksShow.DeleteTask(htCacheShow);
}
}
}
FTMATCHRESULT CFilteredToDoCtrl::MatchFilter(const CTaskFile& tasks, HTASKITEM ht) const
{
FTMATCHRESULT nMatch = FTDC_NOMATCHSTATE;
switch (m_filter.nFilter)
{
case FT_ALL:
nMatch = FTDC_MATCH;
break;
case FT_DONE:
if (IsTaskDone(tasks, ht))
nMatch = FTDC_MATCH;
break;
case FT_NOTDONE:
if (!IsTaskDone(tasks, ht))
nMatch = FTDC_MATCH;
break;
default: // all the rest
if (MatchDueDate(tasks, ht))
nMatch = FTDC_MATCH;
break;
}
// check other values if its a positive match
if (nMatch == FTDC_MATCH)
{
if (!MatchCategory(tasks, ht))
nMatch = FTDC_NOMATCHCATEGORY;
else if (!MatchStatus(tasks, ht))
nMatch = FTDC_NOMATCHSTATUS;
else if (!MatchAllocTo(tasks, ht))
nMatch = FTDC_NOMATCHALLOCTO;
else if (!MatchAllocBy(tasks, ht))
nMatch = FTDC_NOMATCHALLOCBY;
else if (!MatchPriority(tasks, ht))
nMatch = FTDC_NOMATCHPRIORITY;
else if (!MatchRisk(tasks, ht))
nMatch = FTDC_NOMATCHRISK;
}
return nMatch;
}
BOOL CFilteredToDoCtrl::MatchCategory(const CTaskFile& tasks, HTASKITEM ht) const
{
if (m_filter.aCategories.GetSize())
{
CStringArray aCats;
tasks.GetTaskCategories(ht, aCats);
return m_filter.MatchCategories(aCats);
}
// else implicit match
return TRUE;
}
BOOL CFilteredToDoCtrl::MatchStatus(const CTaskFile& tasks, HTASKITEM ht) const
{
if (!m_filter.sStatus.IsEmpty())
return (m_filter.sStatus.CompareNoCase(tasks.GetTaskStatus(ht)) == 0);
// else match
return TRUE;
}
BOOL CFilteredToDoCtrl::MatchAllocTo(const CTaskFile& tasks, HTASKITEM ht) const
{
if (m_filter.aAllocTo.GetSize())
{
CStringArray aAllocTo;
tasks.GetTaskAllocatedTo(ht, aAllocTo);
return m_filter.MatchAllocTo(aAllocTo);
}
// else match
return TRUE;
}
BOOL CFilteredToDoCtrl::MatchAllocBy(const CTaskFile& tasks, HTASKITEM ht) const
{
if (!m_filter.sAllocBy.IsEmpty())
return (m_filter.sAllocBy.CompareNoCase(tasks.GetTaskAllocatedBy(ht)) == 0);
// else match
return TRUE;
}
BOOL CFilteredToDoCtrl::MatchPriority(const CTaskFile& tasks, HTASKITEM ht) const
{
if (m_filter.nPriority != FT_ANYPRIORITY)
{
/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?