windows-nt/Source/XPSP1/NT/shell/shdocvw/util/menu.cpp
2020-09-26 16:20:57 +08:00

306 lines
7.6 KiB
C++

//
// Menu- and menuband- related utility functions
//
#include "local.h"
#include "dochost.h"
// this goes away when the split is done **and** dochost goes away
/*----------------------------------------------------------
Purpose: Replace the contents of hmenuDst with hmenuSrc. Note any
submenus in hmenuDst will be deleted.
Call Menu_RemoveAllSubMenus if you don't want this to
happen.
*/
void Menu_Replace(HMENU hmenuDst, HMENU hmenuSrc)
{
int cItems = GetMenuItemCount(hmenuDst);
int i;
for (i=0; i<cItems; i++)
DeleteMenu(hmenuDst, 0, MF_BYPOSITION);
cItems = GetMenuItemCount(hmenuSrc);
for (i=0; i<cItems; i++)
{
MENUITEMINFO mii;
TCHAR szText[MAX_PATH];
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.dwTypeData = szText;
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA | MIIM_STATE;
mii.cch = ARRAYSIZE(szText);
mii.fType = MFT_SEPARATOR;
mii.hSubMenu = NULL;
mii.dwItemData = 0;
if (GetMenuItemInfo(hmenuSrc, i, TRUE, &mii))
{
HMENU hMenuOldSub = NULL;
if (mii.hSubMenu != NULL)
{
hMenuOldSub = mii.hSubMenu;
mii.hSubMenu = CreateMenu();
Menu_Replace(mii.hSubMenu, hMenuOldSub);
}
InsertMenuItem(hmenuDst, i, TRUE, &mii);
}
}
}
#ifndef POSTPOSTSPLIT
//----------------------------------------------------------------------
//
// CMenuList
//
//----------------------------------------------------------------------
typedef struct
{
HMENU hmenu;
BITBOOL bObject:1; // TRUE: menu belongs to object
} MLITEM; // CMenuList item
CMenuList::CMenuList(void)
{
ASSERT(NULL == _hdsa);
}
CMenuList::~CMenuList(void)
{
if (_hdsa)
{
DSA_Destroy(_hdsa);
_hdsa = NULL;
}
}
/*----------------------------------------------------------
Purpose: Set the menu list (comparable to HOLEMENU) so we can
dispatch commands to the frame or the object correctly.
We do this since menu bands bypass OLE's FrameFilterWndProc.
We build the menu list by comparing the given hmenuShared
with hmenuFrame. Anything in hmenuShared that is not
in hmenuFrame belongs to the object.
*/
void CMenuList::Set(HMENU hmenuShared, HMENU hmenuFrame)
{
ASSERT(NULL == hmenuShared || IS_VALID_HANDLE(hmenuShared, MENU));
ASSERT(NULL == hmenuFrame || IS_VALID_HANDLE(hmenuFrame, MENU));
if (_hdsa)
{
ASSERT(IS_VALID_HANDLE(_hdsa, DSA));
DSA_DeleteAllItems(_hdsa);
}
else
_hdsa = DSA_Create(sizeof(MLITEM), 10);
if (_hdsa && hmenuShared && hmenuFrame)
{
int i;
int iFrame = 0;
int cmenu = GetMenuItemCount(hmenuShared);
int cmenuFrame = GetMenuItemCount(hmenuFrame);
BOOL bMatched;
int iSaveFrame;
int iHaveFrame = -1;
TCHAR sz[64];
TCHAR szFrame[64];
MENUITEMINFO miiFrame;
MENUITEMINFO mii;
MLITEM mlitem;
miiFrame.cbSize = sizeof(miiFrame);
mii.cbSize = sizeof(mii);
for (i = 0; i < cmenu; i++)
{
mii.cch = SIZECHARS(sz);
mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
mii.dwTypeData = sz;
EVAL(GetMenuItemInfo(hmenuShared, i, TRUE, &mii));
ASSERT(IS_VALID_HANDLE(mii.hSubMenu, MENU));
mlitem.hmenu = mii.hSubMenu;
iSaveFrame = iFrame;
bMatched = FALSE;
// DocObject might have dropped some of our menus, like edit and view
// Need to be able to skip over dropped frame menus
while (1)
{
if (iHaveFrame != iFrame)
{
iHaveFrame = iFrame;
if (iFrame < cmenuFrame)
{
miiFrame.cch = SIZECHARS(szFrame);
miiFrame.fMask = MIIM_SUBMENU | MIIM_TYPE;
miiFrame.dwTypeData = szFrame;
EVAL(GetMenuItemInfo(hmenuFrame, iFrame, TRUE, &miiFrame));
}
else
{
// Make it so it won't compare
miiFrame.hSubMenu = NULL;
*szFrame = 0;
}
}
ASSERT(iFrame >= cmenuFrame || IS_VALID_HANDLE(miiFrame.hSubMenu, MENU));
// The browser may have a menu that was not merged into
// the shared menu because the object put one in with
// the same name. Have we hit this case? Check by comparing
// sz and szFrame
if (mii.hSubMenu == miiFrame.hSubMenu || 0 == StrCmp(sz, szFrame))
{
bMatched = TRUE;
break;
}
else
{
if (iFrame >= cmenuFrame)
{
break;
}
iFrame++;
}
}
// Is this one of our menus?
mlitem.bObject = (mii.hSubMenu == miiFrame.hSubMenu) ? FALSE:TRUE;
if (bMatched)
{
iFrame++;
}
else
{
iFrame = iSaveFrame;
}
DSA_SetItem(_hdsa, i, &mlitem);
}
}
}
/*----------------------------------------------------------
Purpose: Adds the given hmenu to the list.
*/
void CMenuList::AddMenu(HMENU hmenu)
{
ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
if (_hdsa && hmenu)
{
MLITEM mlitem;
mlitem.hmenu = hmenu;
mlitem.bObject = TRUE;
DSA_AppendItem(_hdsa, &mlitem);
}
}
/*----------------------------------------------------------
Purpose: Removes the given hmenu from the list.
*/
void CMenuList::RemoveMenu(HMENU hmenu)
{
ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
if (_hdsa && hmenu)
{
int i = DSA_GetItemCount(_hdsa) - 1;
for (; i >= 0; i--)
{
MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
ASSERT(pmlitem);
if (hmenu == pmlitem->hmenu)
{
DSA_DeleteItem(_hdsa, i);
break;
}
}
}
}
/*----------------------------------------------------------
Purpose: Returns TRUE if the given hmenu belongs to the object.
*/
BOOL CMenuList::IsObjectMenu(HMENU hmenu)
{
BOOL bRet = FALSE;
ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
if (_hdsa && hmenu)
{
int i;
for (i = 0; i < DSA_GetItemCount(_hdsa); i++)
{
MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
ASSERT(pmlitem);
if (hmenu == pmlitem->hmenu)
{
bRet = pmlitem->bObject;
break;
}
}
}
return bRet;
}
#ifdef DEBUG
void CMenuList::Dump(LPCTSTR pszMsg)
{
if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU))
{
TraceMsg(TF_ALWAYS, "CMenuList: Dumping menus for %#08x %s", (LPVOID)this, pszMsg);
if (_hdsa)
{
int i;
for (i = 0; i < DSA_GetItemCount(_hdsa); i++)
{
MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
ASSERT(pmlitem);
TraceMsg(TF_ALWAYS, " [%d] = %x", i, pmlitem->hmenu);
}
}
}
}
#endif
#endif