bool MergeMenu(CMenu *pMenuDestination,
const CMenu * pMenuAdd,
bool bTopLevel =false)
Der Parameter pMenuDestination übergibt die Referenz auf das Zielmenü, wo das Menü pMenuAdd angefügt werden soll. Ist bTopLevel TRUE, wird das spezielle Hauptmenü-Handling aktiviert, ansonsten unterdrückt.
Der Rückgabewert der Funktion liefert den Erfolgsstatus der Operation: TRUE für korrekt abgearbeitet, ansonsten FALSE.
bool MergeMenu(CMenu *pMenuDestination,
const CMenu * pMenuAdd,
bool bTopLevel)
{
int iMenuAddItemCount = pMenuAdd->GetMenuItemCount();
int iMenuDestItemCount = pMenuDestination->GetMenuItemCount();
Ist pMenuAdd leer, gibt es nichts zu tun.
if (iMenuAddItemCount == 0)
return true;
Befinden wir uns nicht auf dem Hauptmenü und ist das Zielmenü nicht leer, wird als erstes ein Seperator angefügt...
if (!bTopLevel && iMenuDestItemCount > 0)
{
pMenuDestination->AppendMenu(MF_SEPARATOR);
...bevor dann durch das TopLevel-Menü von pMenuAdd interiert wird. Als erster Schritt fällt für jeden Durchlauf das Ermitteln des entsprechenden Strings an.
for(int iLoop = 0; iLoop < iMenuAddItemCount; iLoop++)
{
CString sMenuAddString;
pMenuAdd->GetMenuString(iLoop, sMenuAddString, MF_BYPOSITION);
Es folgt der Versuch, das Untermenü des aktuellen Menüpunkts zu adressieren. Schlägt dies fehl, existiert zum aktuellen Menüpunkt kein Untermenü.
CMenu* pSubMenu = pMenuAdd->GetSubMenu(iLoop);
Liegt kein Untermenü vor, handelt es sich um einen normalen Menüpunkt, bei dem die Quelle gelesen und im Zielmenü eingefügt wird. Gelingt dieser Schritt, darf nicht vergessen werden, den Item-Zähler um 1 zu erhöhen.
if (!pSubMenu)
{
UINT nState = pMenuAdd->GetMenuState(iLoop, MF_BYPOSITION);
UINT nItemID = pMenuAdd->GetMenuItemID(iLoop);
if (pMenuDestination->AppendMenu(nState, nItemID,
sMenuAddString))
iMenuDestItemCount++;
}
else
{
TRACE("MergeMenu: AppendMenu fehlgeschlagen!\n");
return false;
}
}
Liegt hingegen ein Untermenü vor, gilt es, ein neues Popup-Menü zu erzeugen oder einzufügen. Befindet sich die Einfügeposition im TopLevel, wird anstelle eines neu erzeugten Menüs ein vorhandenes eingefügt.
else
{
int iInsertPosDefault = -1;
if(bTopLevel)
{
ASSERT(sMenuAddString != "&?" && sMenuAddString != "?");
CString csAdd(sMenuAddString);
csAdd.Remove('&');
bool bAdded = false;
Bei der Suche nach dem eventuell vorhandenen String erfolgt der Stringvergleich auf den reinen Text ohne das Zeichen „&“. Dieses wurde oben bereits für die Quelle entfernt. Analog wird nachfolgend auch das „&“ aus dem Zielstring für den Vergleich entfernt.
for(int iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++)
{
CString sDest;
pMenuDestination->GetMenuString(iLoop1, sDest,
MF_BYPOSITION);
sDest.Remove('&');
Stimmen die beiden Menüs überein, werden die beiden Popup-Menüs verschmolzen. Dazu wird ein Zeiger auf das Zielmenü ermittelt. Anschließend werden die beiden Menüs rekursiv verschmolzen.
if (csAdd == sDest)
{
CMenu* pSubMenuDest = pMenuDestination->GetSubMenu(
iLoop1);
if (pSubMenuDest)
{
if (!MergeMenu(pSubMenuDest, pSubMenu))
{
return false;
}
bAdded = true;
break;
}
}
Danach wird mit der äußeren Schleife fortgefahren.
Konnte hingegen keine Übereinstimmung gefunden werden, fügt die Funktion das Quellmenü im Hauptmenü ein. Die Einfügeposition ergibt sich entweder als Ende des Menüs, was durch -1 gekennzeichnet wird oder direkt links neben dem Menüpunkt „Fenster“ oder „Hilfe“ bzw. „?“.
if (iInsertPosDefault == -1 &&
(sDest == "Fenster" || sDest == "?" ||
sDest == "Hilfe"))
{
iInsertPosDefault = iLoop1;
}
} // for (iLoop1)
Konnte das Menü eingefügt werden, geht es weiter mit der Schleife über das TopLevel-Menü von pMenuAdd.
if (bAdded)
{
continue;
}
} // if (bTopLevel)
Ergab die TopLevel-Suche keine Einfügeposition, wird das Menü angehängt.
if( iInsertPosDefault == -1 )
{
iInsertPosDefault = pMenuDestination->GetMenuItemCount();
}
Dazu wird zunächst ein neues Popup-Menü in NewPopupMenu erzeugt...
CMenu NewPopupMenu;
if (!NewPopupMenu.CreatePopupMenu())
{
TRACE("MergeMenu: CreatePopupMenu fehlgeschlagen!\n");
return false;
}
...und anschließend über rekursive Aufrufe vor „Fenster“ und „Hilfe“ eingefügt.
if (!MergeMenu(&NewPopupMenu,pSubMenu))
{
return false;
}
Das neue Popup-Menü kann nun in das Zielmenü eingefügt werden, wobei wiederum nicht zu vergessen ist, den Item-Zähler zu inkrementieren, da ansonsten die Schleifendurchläufe durcheinander geraten.
HMENU hNewMenu = NewPopupMenu.GetSafeHmenu();
if (pMenuDestination->InsertMenu(iInsertPosDefault,
MF_BYPOSITION | MF_POPUP | MF_ENABLED,
(UINT)hNewMenu, sMenuAddString ))
{
iMenuDestItemCount++;
}
else
{
TRACE("MergeMenu: InsertMenu fehlgeschlagen!\n");
return false;
}
Das neue Popup-Menü darf jetzt natürlich nicht zerstört werden, so daß ein Aufruf von Detach() erforderlich wird.
NewPopupMenu.Detach();
} // if (pSubMenu)
} // for (iLoop)
Der Rückgabewert der Funktion lautet nach Abarbeiten aller Schleifen TRUE.
return true;
}
Erweiterungen
Bei Bedarf kann die Einsortierung des Menüs vor „Fenster“ und „Hilfe“ dahingehend erweitert werden, daß beliebige Strings über einen zusätzlichen Parameter vorgegeben werden. Dies wurde hier jedoch nicht implementiert, da es in der Praxis wohl selten benötigt wird.
|