📄 tabbedmdisave.cpp
字号:
bool success = true;
long count = 0;
list->get_Count(&count);
for(long i=0; i<count; ++i)
{
ATL::CComPtr<ITabbedMDIChildModifiedItem> item;
list->get_Item(i, &item);
if(item)
{
ATL::CComBSTR displayName, description;
item->get_DisplayName(&displayName);
item->get_Description(&description);
DATE lastModified = 0;
item->get_LastModifiedUTC(&lastModified);
_CSTRING_NS::CString displayNameForItem(displayName);
_CSTRING_NS::CString descriptionForItem(description);
_CSTRING_NS::CString lastModifiedForItem = this->FormatLastModifiedDateString(lastModified);
if(displayNameForItem.GetLength() < 1)
{
displayNameForItem = _T("(New)");
}
int imageIndex = 0;
HICON hIcon = NULL;
item->get_Icon(&hIcon);
if(hIcon != NULL)
{
imageIndex = m_images.AddIcon(hIcon);
}
// NOTE: The handler of LVN_INSERTITEM will AddRef,
// and the handler of LVN_DELETEITEM will Release
// to be sure we keep the item reference counted appropriately
// no matter where the InsertItem comes from.
//IUnknown* punkItem = NULL;
ATL::CComPtr<IUnknown> punkItem;
item->QueryInterface(IID_IUnknown, (void**)&punkItem);
LVITEM lvItem = {0};
lvItem.mask = (LVIF_TEXT | LVIF_INDENT | LVIF_IMAGE | LVIF_PARAM);
lvItem.iItem = m_list.GetItemCount();
lvItem.iSubItem = 0;
lvItem.pszText = (LPTSTR)(LPCTSTR)displayNameForItem;
lvItem.iIndent = indent;
lvItem.iImage = imageIndex;
lvItem.lParam = (LPARAM)punkItem.p;
int index = m_list.InsertItem(&lvItem);
if(index >= 0)
{
m_list.SetCheckState(index, TRUE);
m_list.SetItemText(index, eColumn_Description, descriptionForItem);
if(lastModifiedForItem.GetLength() > 0)
{
m_haveAtLeastOneModifiedDate = true;
m_list.SetItemText(index, eColumn_LastModified, lastModifiedForItem);
}
}
ATL::CComPtr<ITabbedMDIChildModifiedList> subItems;
item->get_SubItems(&subItems);
if(subItems)
{
this->AddItems(subItems, (indent + 1));
}
}
}
return success;
}
_CSTRING_NS::CString CSaveModifiedItemsDialog::FormatLastModifiedDateString(DATE lastModifiedUTC)
{
_CSTRING_NS::CString lastModifiedString;
if(lastModifiedUTC != 0)
{
SYSTEMTIME lastModifiedUTCSystem = {0};
::VariantTimeToSystemTime(lastModifiedUTC, &lastModifiedUTCSystem);
FILETIME lastModifiedUTCFileTime = {0};
::SystemTimeToFileTime(&lastModifiedUTCSystem, &lastModifiedUTCFileTime);
FILETIME lastModifiedLocalFileTime = {0};
::FileTimeToLocalFileTime(&lastModifiedUTCFileTime, &lastModifiedLocalFileTime);
COleDateTime nowLocal(COleDateTime::GetCurrentTime());
COleDateTime dateTimeModifiedLocal(lastModifiedLocalFileTime);
_CSTRING_NS::CString fullDateTimeString = dateTimeModifiedLocal.Format(_T("%#m/%#d/%Y %#I:%M %p"));;
_CSTRING_NS::CString timeString = dateTimeModifiedLocal.Format(_T("%#I:%M %p"));;
int yearDifference = (nowLocal.GetYear() - dateTimeModifiedLocal.GetYear());
int dayOfYearDifference = (nowLocal.GetDayOfYear() - dateTimeModifiedLocal.GetDayOfYear());
int hourDifference = (nowLocal.GetHour() - dateTimeModifiedLocal.GetHour());
int minuteDifference = (nowLocal.GetMinute() - dateTimeModifiedLocal.GetMinute());
int secondDifference = (nowLocal.GetSecond() - dateTimeModifiedLocal.GetSecond());
if( yearDifference >= 1 ||
dayOfYearDifference > 1 ||
nowLocal < dateTimeModifiedLocal)
{
lastModifiedString = fullDateTimeString;
}
else if(dayOfYearDifference == 1)
{
lastModifiedString.Format(_T("Yesterday, %s"), timeString);
}
else if(hourDifference >= 1)
{
lastModifiedString.Format(_T("%d hour%s ago"), hourDifference,
(hourDifference!=1) ? _T("s") : _T(""));
}
else if(minuteDifference >= 1)
{
lastModifiedString.Format(_T("%d minute%s ago"), minuteDifference,
(minuteDifference!=1) ? _T("s") : _T(""));
}
else if(secondDifference >= 1)
{
lastModifiedString.Format(_T("%d second%s ago"), secondDifference,
(secondDifference!=1) ? _T("s") : _T(""));
}
else
{
lastModifiedString = fullDateTimeString;
}
}
return lastModifiedString;
}
IUnknown* CSaveModifiedItemsDialog::GetIUnknownForItem(int index)
{
LVITEM lvi={0};
lvi.mask = LVIF_PARAM;
lvi.iItem = index;
lvi.iSubItem = 0;
lvi.lParam = 0;
if(m_list.GetItem(&lvi))
{
return (IUnknown*) lvi.lParam;
}
return NULL;
}
int CSaveModifiedItemsDialog::FindItemIndex(ITabbedMDIChildModifiedItem* item)
{
if(item == NULL)
{
return -1;
}
ATL::CComPtr<IUnknown> punkNode;
item->QueryInterface(IID_IUnknown, (void**)&punkNode);
if(punkNode)
{
LVFINDINFO findInfo = {0};
findInfo.flags = LVFI_PARAM;
findInfo.lParam = (LPARAM)(IUnknown*)punkNode.p;
return m_list.FindItem(&findInfo, -1);
}
return -1;
}
int CSaveModifiedItemsDialog::FindParentIndex(int item)
{
// Find the index of the "parent" based on the indent
LVITEM lvi = { 0 };
lvi.iItem = item;
lvi.iSubItem = 0;
lvi.mask = LVIF_INDENT;
m_list.GetItem(&lvi);
if(lvi.iIndent == 0)
{
return -1;
}
int parentIndex = -1;
for(int i=item; (i >= 0) && (parentIndex < 0); --i)
{
LVITEM lviParent = { 0 };
lviParent.iItem = i;
lviParent.iSubItem = 0;
lviParent.mask = LVIF_INDENT;
m_list.GetItem(&lviParent);
if(lviParent.iIndent < lvi.iIndent)
{
// We've hit the first item before the
// item in question where the indent is less.
// Treat this as the parent
parentIndex = i;
}
}
return parentIndex;
}
void CSaveModifiedItemsDialog::ToggleCheckState(int item)
{
LVITEM lvi = { 0 };
lvi.iItem = item;
lvi.iSubItem = 0;
lvi.mask = (LVIF_INDENT | LVIF_STATE);
lvi.stateMask = (LVIS_STATEIMAGEMASK | LVIS_SELECTED);
m_list.GetItem(&lvi);
CheckState checkState = (CheckState)(lvi.state & LVIS_STATEIMAGEMASK);
CheckState newCheckState = eCheckState_Checked;
switch(checkState)
{
case eCheckState_Unchecked:
newCheckState = eCheckState_Checked;
break;
case eCheckState_Checked:
newCheckState = eCheckState_Unchecked;
break;
case eCheckState_Indeterminate:
newCheckState = eCheckState_Checked;
break;
}
if((lvi.state & LVIS_SELECTED) != LVIS_SELECTED)
{
// If the item isn't selected, toggle the checkmark on just the item
this->SetTristateCheckState(item, newCheckState);
}
else
{
// Otherwise, set the checkmark appropriately on all selected items.
int itemToCheck = -1;
while((itemToCheck = m_list.GetNextItem(itemToCheck, LVNI_SELECTED)) != -1)
{
this->SetTristateCheckState(itemToCheck, newCheckState);
}
}
}
void CSaveModifiedItemsDialog::SetTristateCheckState(int item, CheckState checkState)
{
LVITEM lvi = { 0 };
lvi.iItem = item;
lvi.iSubItem = 0;
lvi.mask = LVIF_INDENT;
m_list.GetItem(&lvi);
int itemToCheck = item;
bool done = false;
// Set the check of the item as well as all of the "child" items
while(!done)
{
m_list.SetItemState(itemToCheck, checkState, LVIS_STATEIMAGEMASK);
itemToCheck = m_list.GetNextItem(itemToCheck, LVNI_ALL);
if(itemToCheck < 0)
{
done = true;
}
else
{
LVITEM lviToCheck = { 0 };
lviToCheck.iItem = itemToCheck;
lviToCheck.iSubItem = 0;
lviToCheck.mask = LVIF_INDENT;
m_list.GetItem(&lviToCheck);
done = (lviToCheck.iIndent <= lvi.iIndent);
}
}
this->UpdateParentCheckState(item, checkState);
}
CSaveModifiedItemsDialog::CheckState CSaveModifiedItemsDialog::GetTristateCheckState(int item)
{
return (CheckState)m_list.GetItemState(item, LVIS_STATEIMAGEMASK);
}
void CSaveModifiedItemsDialog::UpdateParentCheckState(int item, CheckState checkState)
{
// Update the "parent" item's checkbox to reflect the state of the descendants.
// If all of the descendants are checked, then check the parent.
// If all of the descendants are unchecked, then uncheck the parent.
// If some of the descendants are checked, and some are unchecked, have
// the parent's checkbox be indeterminate.
// If the parent isn't a "root" parent, recursively give the same
// treatment to all of the ancestors.
int parentIndex = this->FindParentIndex(item);
if(parentIndex >= 0)
{
LVITEM lviParent = { 0 };
lviParent.iItem = parentIndex;
lviParent.iSubItem = 0;
lviParent.mask = LVIF_INDENT;
m_list.GetItem(&lviParent);
int itemToCheck = parentIndex + 1;
bool checkStateMixed = false;
bool done = false;
while(!done)
{
LVITEM lviDescendant = { 0 };
lviDescendant.iItem = itemToCheck;
lviDescendant.iSubItem = 0;
lviDescendant.mask = (LVIF_INDENT | LVIF_STATE);
lviDescendant.stateMask = LVIS_STATEIMAGEMASK;
BOOL validItem = m_list.GetItem(&lviDescendant);
if(!validItem)
{
done = true;
}
else if(lviDescendant.iIndent <= lviParent.iIndent)
{
// There's no more possible siblings or descendants,
// because we've hit our parent's sibling
done = true;
}
else
{
CheckState descendantCheckState = (CheckState)(lviDescendant.state & LVIS_STATEIMAGEMASK);
if(descendantCheckState != checkState)
{
checkStateMixed = true;
done = true;
}
}
if(!done)
{
itemToCheck = m_list.GetNextItem(itemToCheck, LVNI_ALL);
done = (itemToCheck < 0);
}
}
// Now we've visited all of the descendants of the parent.
// If all of them have the same check state as the item,
// set the parent's check state to the same. If the descendants
// have mixed check states, then set the parent's check
// state to indeterminate.
if(checkStateMixed)
{
m_list.SetItemState(parentIndex, eCheckState_Indeterminate, LVIS_STATEIMAGEMASK);
}
else
{
m_list.SetItemState(parentIndex, checkState, LVIS_STATEIMAGEMASK);
}
this->UpdateParentCheckState(parentIndex, checkState);
}
}
void CSaveModifiedItemsDialog::CreateDefaultImages(void)
{
// IMPORTANT! Win2K and WinXP have the same index for this bitmap.
// There's even a standard TB_LOADIMAGES message for toolbar that loads it,
// along with standard image indexes into the bitmap.
// However, instead of creating a toolbar and issuing TB_LOADIMAGES,
// we'll load the bitmap directly by its index (120) and
// the color mask (192,192,192).
// Double check future versions of Windows to make sure
// this all works correctly.
HMODULE hComCtl32 = GetModuleHandle(_T("comctl32.dll"));
if(hComCtl32)
{
HIMAGELIST hCommonToolbar = ImageList_LoadBitmap(hComCtl32, MAKEINTRESOURCE(120), 16, 0, RGB(192,192,192));
if(hCommonToolbar)
{
HICON hFileNew = ImageList_ExtractIcon(NULL, hCommonToolbar, STD_FILENEW);
HICON hFileSave = ImageList_ExtractIcon(NULL, hCommonToolbar, STD_FILESAVE);
if(hFileNew)
{
int fileNewIndex = m_images.AddIcon(hFileNew);
ATLASSERT(fileNewIndex == 0);
::DestroyIcon(hFileNew);
hFileNew = NULL;
}
if(hFileSave)
{
int fileSaveIndex = m_images.AddIcon(hFileSave);
ATLASSERT(fileSaveIndex == 1);
m_dialogIcon = hFileSave;
this->SetIcon(m_dialogIcon, ICON_SMALL);
}
ImageList_Destroy(hCommonToolbar);
hCommonToolbar = NULL;
}
}
}
void CSaveModifiedItemsDialog::CreateDefaultStateImages(void)
{
if(!m_stateImages.IsNull())
{
WTL::CWindowDC dcScreen(NULL);
int cx = ::GetSystemMetrics(SM_CXSMICON);
int cy = ::GetSystemMetrics(SM_CYSMICON);
m_imageUnchecked = this->AddCheckStateImage(dcScreen, cx, cy, eCheckState_Unchecked);
m_imageChecked = this->AddCheckStateImage(dcScreen, cx, cy, eCheckState_Checked);
m_imageIndeterminate = this->AddCheckStateImage(dcScreen, cx, cy, eCheckState_Indeterminate);
}
}
int CSaveModifiedItemsDialog::AddCheckStateImage(HDC dcScreen, int cx, int cy, enum CheckState checkState)
{
ImageUtil::eCheckbox type = ImageUtil::eCheckboxChecked;
switch(checkState)
{
case eCheckState_Unchecked:
type = ImageUtil::eCheckboxUnchecked;
break;
case eCheckState_Checked:
type = ImageUtil::eCheckboxChecked;
break;
case eCheckState_Indeterminate:
type = ImageUtil::eCheckboxIndeterminate;
break;
default:
ATLASSERT(0 && "Invalid checkbox type!");
break;
}
int index = -1;
WTL::CBitmap bitmap = ImageUtil::CreateCheckboxImage(dcScreen, type, cx, cy, RGB(255,0,0), m_list);
if(!bitmap.IsNull())
{
index = m_stateImages.Add(bitmap, RGB(255,0,0));
}
return index;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -