todoctrl.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 2,301 行 · 第 1/5 页
CPP
2,301 行
rTree.bottom = (rCtrls.top - dlu.ToPixelsY(CTRLVSPACING));
}
dwm.MoveWindow(GetDlgItem(IDC_TASKLIST), rTree);
// project name
dwm.ResizeCtrl(this, IDC_PROJECTNAME, rTree.right - rProject.right, 0);
// now iterate the visible controls settings their positions dynamically
CRect rItem(rCtrls);
rItem.bottom = rItem.top + dlu.ToPixelsY(CTRLHEIGHT);
int nCol = 0;
int nRightEdge = bVertComments ? rCtrls.right : rCtrls.right - dlu.ToPixelsY(CTRLHSPACING);
for (int nCtrl = 0; nCtrl < NUM_CTRLITEMS; nCtrl++)
{
if (!bAllVisible && !IsColumnShowing(CTRLITEMS[nCtrl].nCol))
continue;
if (nCol >= nCols)
{
nCol = 0;
rItem.OffsetRect(0, dlu.ToPixelsY(CTRLHEIGHT + CTRLVSPACING));
}
ReposControl(nCtrl, &dwm, &dlu, nCol, rItem.top, nRightEdge);
nCol++;
}
}
UpdateWindow();
}
}
int CToDoCtrl::GetMinNonCommentSize()
{
if (HasStyle(TDCS_VERTCOMMENTS))
{
// two field widths
CDlgUnits dlu(*this);
return dlu.ToPixelsX(2 * (CTRLENDOFFSET + CTRLHSPACING));
}
else
return MINNONCOMMENTHEIGHT;
}
void CToDoCtrl::ReposComments(int cx, int cy, CDeferWndMove* pDWM, CRect& rComments /*out*/)
{
// validate comments size but don't change it
int nCommentSize = HasStyle(TDCS_SHAREDCOMMENTSHEIGHT) ? s_nCommentsSize : m_nCommentsSize;
if (HasStyle(TDCS_VERTCOMMENTS))
{
nCommentSize = min(nCommentSize, cx - GetMinNonCommentSize());
rComments.top = 2;
rComments.left = cx - nCommentSize;
}
else
{
nCommentSize = min(nCommentSize, cy - GetMinNonCommentSize());
rComments.left = 0;
rComments.top = cy - nCommentSize;
}
rComments.right = cx; // always
rComments.bottom = cy; // always
CRect rComField(rComments);
// horizontal splitter
if (!HasStyle(TDCS_VERTCOMMENTS))
{
CRect rDiv(rComments);
rDiv.bottom = rDiv.top + 2;
pDWM->MoveWindow(GetDlgItem(IDC_HSPLITTER), rDiv);
rComField.top = rDiv.bottom+ 4;
}
// label
CRect rItem = pDWM->MoveCtrl(this, IDC_COMMENTSLABEL, rComField.left, rComField.top);
// type combo to right of label
if (m_mgrContent.GetNumContent() > 1)
rItem = pDWM->MoveCtrl(this, IDC_COMMENTSTYPE, rItem.right + 4, rItem.top);
// comments below combo
rComField.top = rItem.bottom + 4;
pDWM->MoveWindow(GetDlgItem(IDC_COMMENTS), rComField);
}
void CToDoCtrl::ReposControl(int nCtrl, CDeferWndMove* pDWM, const CDlgUnits* pDLU, int nCol,
int nTop, int nClientRight)
{
// the bottom of the ctrl is defined by its existing height
CRect rItem(0, nTop, 0, nTop + ResizeCtrl(CTRLITEMS[nCtrl].nCtrlID).Height());
rItem.left = pDLU->ToPixelsX(nCol * (CTRLENDOFFSET + CTRLHSPACING));
rItem.right = rItem.left + pDLU->ToPixelsX(CTRLENDOFFSET);
// move label
CRect rLabel(rItem);
rLabel.right = rLabel.left + pDLU->ToPixelsX(CTRLSTARTOFFSET - CTRLHSPACING);
pDWM->MoveWindow(GetDlgItem(CTRLITEMS[nCtrl].nLabelID), rLabel);
// move control
CRect rCtrl(rItem);
rCtrl.left += pDLU->ToPixelsX(CTRLSTARTOFFSET);
// some special cases
switch (CTRLITEMS[nCtrl].nCtrlID)
{
case IDC_PERCENT:
{
CRect rSpin = OffsetCtrl(IDC_PERCENTSPIN); // gets current pos
rSpin.OffsetRect(rCtrl.right - rSpin.right, 0);
rSpin.top = rCtrl.top;
rSpin.bottom = rCtrl.bottom;
pDWM->MoveWindow(&m_spinPercent, rSpin);
rCtrl.right = rSpin.left + 2;
}
break;
case IDC_FILEPATH:
{
// file path control can take as much space as is left
rCtrl.right = nClientRight;
}
break;
case IDC_ALLOCTO:
case IDC_ALLOCBY:
case IDC_STATUS:
case IDC_CATEGORY:
case IDC_PRIORITY:
case IDC_VERSION:
rCtrl.bottom += 200; // combo box drop height
break;
}
pDWM->MoveWindow(GetDlgItem(CTRLITEMS[nCtrl].nCtrlID), rCtrl);
}
int CToDoCtrl::VisibleCtrlCount()
{
if (!HasStyle(TDCS_SHOWCTRLSASCOLUMNS))
return NUM_CTRLITEMS;
// else
int nVisibleCtrls = 0;
for (int nCtrl = 0; nCtrl < NUM_CTRLITEMS; nCtrl++)
{
if (IsColumnShowing(CTRLITEMS[nCtrl].nCol))
nVisibleCtrls++;
}
return nVisibleCtrls;
}
int CToDoCtrl::GetMinWidth()
{
int nMinWidth = CDlgUnits(*this).ToPixelsX(2 * (CTRLENDOFFSET + CTRLHSPACING) + 1);
return nMinWidth;
}
// wrapper for CTreeCtrl
BOOL CToDoCtrl::SetCheckImageList(HIMAGELIST hImageList)
{
m_hilDone = hImageList;
if (HasStyle(TDCS_TREECHECKBOXES))
TreeView_SetImageList(m_tree, m_hilDone, TVSIL_STATE);
return TRUE;
}
void CToDoCtrl::OnTreeSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTREEVIEW pNMTV = (LPNMTREEVIEW)pNMHDR;
HTREEITEM hti = pNMTV->itemNew.hItem;
*pResult = 0;
// we don't support nothing having being selected unless there
// are no items in the tree
BOOL bCtrl = Misc::KeyIsPressed(VK_CONTROL) && (s_nExtendedSelection & HOTKEYF_CONTROL);
BOOL bShift = Misc::KeyIsPressed(VK_SHIFT) && (s_nExtendedSelection & HOTKEYF_SHIFT);
// cursor handled here
// <shift>+cursor handled here
// <ctrl>+cursor handled in PreTranslateMessage
// <ctrl>+<shift>+cursor handled in PreTranslateMessage
if (m_wKeyPress)
{
switch (m_wKeyPress)
{
case VK_NEXT:
case VK_DOWN:
case VK_UP:
case VK_PRIOR:
case VK_RIGHT:
case VK_LEFT:
case VK_HOME:
case VK_END:
if (!bCtrl)
{
Selection().RemoveAll();
if (bShift)
Selection().AddItems(Selection().GetAnchor(), hti);
else
{
Selection().SetAnchor(hti);
Selection().AddItem(hti);
}
}
break;
default:
// else handle alphanum method of changing selection
Selection().RemoveAll();
Selection().SetAnchor(hti);
Selection().AddItem(hti);
break;
}
m_wKeyPress = 0;
}
// handle user clicking in the tree but not on an item
// just set the focus back to the tree and do not update anything
else if (hti == NULL)
{
hti = GetSelectedItem();
if (hti)
m_tree.SetItemState(hti, TVIS_SELECTED, TVIS_SELECTED);
return;
}
UpdateControls(hti); // load newly selected item
UpdateSelectedTaskPath();
}
void CToDoCtrl::UpdateSelectedTaskPath()
{
// add the item path to the header
if (HasStyle(TDCS_SHOWPATHINHEADER))
{
CEnString sHeader(IDS_TDC_TASK);
if (GetSelectedCount() == 1)
{
CString sPath = GetSelectedTaskPath();
if (!sPath.IsEmpty())
sHeader.Format("%s [%s]", CEnString(IDS_TDC_TASK), sPath);
}
m_tree.SetGutterColumnHeaderTitle(TDCC_CLIENT, sHeader);
}
}
CString CToDoCtrl::GetSelectedTaskPath()
{
return m_tree.TCH().GetItemPath(GetSelectedItem(), 20);
}
void CToDoCtrl::UpdateControls(HTREEITEM hti)
{
if (!hti)
hti = GetSelectedItem();
int nSelCount = GetSelectedCount();
BOOL bMaximize = HasStyle(TDCS_MAXIMIZE);
BOOL bEnable = (hti && !bMaximize);
BOOL bIsParent = Selection().ItemsAreAllParents();
BOOL bAveSubTaskCompletion = HasStyle(TDCS_AVERAGEPERCENTSUBCOMPLETION) && bIsParent;
BOOL bShowCtrlsAsCols = HasStyle(TDCS_SHOWCTRLSASCOLUMNS);
BOOL bReadOnly = IsReadOnly();
BOOL bEditTime = !bIsParent || HasStyle(TDCS_ALLOWPARENTTIMETRACKING);
// BOOL bEditCost = !bIsParent;
BOOL bEditDue = (nSelCount >= 1);
BOOL bIsClocking = m_data.IsTaskTimeTrackable(hti) && (GetSelectedTaskID() == m_dwTimeTrackTaskID);
BOOL bEditPercent = !HasStyle(TDCS_AUTOCALCPERCENTDONE) && (nSelCount > 1 || !bAveSubTaskCompletion);
BOOL bEditColor = !HasStyle(TDCS_COLORTEXTBYCATEGORY) && !HasStyle(TDCS_COLORTEXTBYPRIORITY);
BOOL bEditComments = FALSE;
CString sCommentsType(m_cfDefault);
if (hti)
{
m_sTextComments = GetSelectedTaskComments();
m_nPriority = (int)GetSelectedTaskPriority();
m_nRisk = (int)GetSelectedTaskRisk();
m_sAllocBy = GetSelectedTaskAllocBy();
m_sStatus = GetSelectedTaskStatus();
m_sFileRefPath = GetSelectedTaskFileRef();
m_sExternalID = GetSelectedTaskExtID();
m_sDepends = GetSelectedTaskDependency();
m_sVersion = GetSelectedTaskVersion();
m_crColour = GetSelectedTaskColor();
// can only edit comments if the comments type for the task is available
m_CustomComments = GetSelectedTaskCustomComments(sCommentsType);
bEditComments = (m_mgrContent.FindContent(sCommentsType) != -1);
// special cases
GetSelectedTaskCategories(m_aCategory);
GetSelectedTaskAllocTo(m_aAllocTo);
if (bEditTime)
{
m_dTimeEstimate = GetSelectedTaskTimeEstimate(m_nTimeEstUnits);
m_dTimeSpent = GetSelectedTaskTimeSpent(m_nTimeSpentUnits);
}
else
{
m_nTimeEstUnits = m_nTimeSpentUnits = s_tdDefault.nTimeEstUnits;
m_dTimeEstimate = m_data.CalcTimeEstimate(hti, m_nTimeEstUnits);
m_dTimeSpent = m_data.CalcTimeSpent(hti, m_nTimeEstUnits);
}
// if (bEditCost)
m_dCost = GetSelectedTaskCost();
// else
// m_dCost = m_data.CalcCost(hti);
// chess clock for time spent
DWORD dwSelTaskID = GetSelectedTaskID();
m_eTimeSpent.CheckButton(ID_TIMEEDITBTN, (dwSelTaskID == m_dwTimeTrackTaskID));
m_eTimeSpent.EnableButton(ID_TIMEEDITBTN, bEditTime && bEnable && !bReadOnly &&
nSelCount == 1 && m_data.IsTaskTimeTrackable(hti));
// dependency link button
m_eDependency.EnableButton(ID_DEPENDS_LINK, bEnable && !bReadOnly && !m_sDepends.IsEmpty());
// percent done
if (IsSelectedTaskDone())
m_nPercentDone = 100;
else if (bEditPercent)
m_nPercentDone = GetSelectedTaskPercent();
else
m_nPercentDone = m_data.CalcPercentDone(hti);
// date controls need special handling too
COleDateTime date;
if (bEditDue)
date = GetSelectedTaskDate(TDCD_DUE);
else
date = m_data.GetEarliestDueDate(hti, HasStyle(TDCS_USEEARLIESTDUEDATE));
SetCtrlDate(m_dateDue, date);
SetCtrlDate(m_dateDone, GetSelectedTaskDate(TDCD_DONE));
SetCtrlDate(m_dateStart, GetSelectedTaskDate(TDCD_START));
// recurrence
GetSelectedTaskRecurrence(m_tRecurrence);
m_eRecurrence.SetDefaultDate(date);
}
else // clear controls
{
m_sTextComments.Empty();
m_CustomComments.Empty();
m_nPriority = 0;
m_nRisk = 0;
m_sAllocBy.Empty();
m_sStatus.Empty();
m_sFileRefPath.Empty();
m_sExternalID.Empty();
m_sDepends.Empty();
m_nPercentDone = 0;
m_dTimeEstimate = m_dTimeSpent = 0;
m_dCost = 0;
m_tRecurrence = TDIRECURRENCE();
m_sVersion.Empty();
m_crColour = GetSysColor(COLOR_WINDOWTEXT);
m_aCategory.RemoveAll();
m_aAllocTo.RemoveAll();
COleDateTime date;
SetCtrlDate(m_dateDue, date);
SetCtrlDate(m_dateDone, date);
SetCtrlDate(m_dateStart, date);
m_eTimeSpent.EnableButton(ID_TIMEEDITBTN, FALSE);
m_eDependency.EnableButton(ID_DEPENDS_LINK, FALSE);
}
// recreate comments control if necessary
// note: if more than one comments type is selected then sCommentsType
// will be empty which will put the comments type combo in an
// indeterminate state which is the desired effect since this requires
// the user to reset the type before they can edit
m_cfComments = sCommentsType;
m_cbCommentsType.SetSelectedFormat(m_cfComments);
if (!sCommentsType.IsEmpty())
CreateContentControl();
// update control content
UpdateData(FALSE);
UpdateComments(FALSE);
// now enable/disable appropriate controls
for (int nCtrl = 0; nCtrl < NUM_CTRLITEMS; nCtrl++)
{
CWnd* pCtrl = GetDlgItem(CTRLITEMS[nCtrl].nCtrlID);
CWnd* pLabel = GetDlgItem(CTRLITEMS[nCtrl].nLabelID);
if (!pCtrl || !pLabel)
continue;
BOOL bCtrlShowing = !bMaximize && (!bShowCtrlsAsCols || IsColumnShowing(CTRLITEMS[nCtrl].nCol));
int nShowCtrl = bCtrlShowing ? SW_SHOW : SW_HIDE;
// control state
RT_CTRLSTATE nState = (!bEnable || !bCtrlShowing) ? RTCS_DISABLED :
(bReadOnly ? RTCS_READONLY : RTCS_ENABLED);
// some additions and modifications
switch (CTRLITEMS[nCtrl].nCtrlID)
{
case IDC_PERCENT:
if (!bEditPercent && bEnable)
nState = RTCS_READONLY;
m_spinPercent.ShowWindow(nShowCtrl);
SetControlState(m_spinPercent, nState);
break;
case IDC_TIMEEST:
if (!bEditTime && bEnable)
nState = RTCS_READONLY;
break;
case IDC_TIMESPENT:
if ((!bEditTime || bIsClocking) && bEnable)
nState = RTCS_READONLY;
break;
// case IDC_COST:
// if (!bEditCost && bEnable)
// nState = RTCS_READONLY;
// break;
case IDC_COLOUR:
if (!bEditColor)
nState = RTCS_DISABLED;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?