| 1001010.com |
one zero zero one zero one zero dot com |
Hmm, that's not the best title - but maybe a contrived code sample or two will help out in explaining why sometimes I weep when I look at certain bits of code.
Imagine if you would, creating a context menu with a few dynamic elements without IDs
menu->append("Hello");
menu->append("This");
menu->append("is a");
menu->append("Test");
And you responded to the elements not by an ID number, but by a position index.
switch(selectedIndex):
{
case 0: doHello(); break;
case 1: doThis(); break;
case 2: doIsA(); break;
case 3: doTest(); break;
}
And then when you look at the code that creates the menu item with greater scrutiny, you notice it's not as simple as you once thought...
menu->append("Hello");
if(hasPermission(SECURITY_RIGHTS_THIS))
menu->append("This");
menu->append("is a");
menu->append("Test");
That's why I wept.
If an unlucky user doesn't have SECURITY_RIGHTS_THIS all the following menu items will be off by one!
This isn't a hard coded COM interface contract, but it IS a handshake usage contract that a future maintenance programmer (such as myself) may not even be aware of!
So here's a simple solution (if you can't change it to use proper IDs because it would effect to many systems):
Keep a table of what menu items were added and their appended menu index. Maybe something along the lines of
enum PossibleMenuItems { pmiHello, pmiThis, pmiIsA, pmiTest, pmi_MAX };
typedef map<int, PossibleMenuItems> IndexToMenuItem;
IndexToMenuItem m_IndexToCommand;
...
int nMenuIndex = 0;
// For each item you add, append it AND record it...
menu->append("Hello");
m_IndexToCommand[nMenuIndex++] = pmiHello;
if(hasPermission(SECURITY_RIGHTS_THIS))
{
menu->append("This");
m_IndexToCommand[nMenuIndex++] = pmiThis;
}
...
Then in the menu handler...
IndexToMenuItem::iterator itFind = m_IndexToCommand.find(selectedIndex);
if( itFind != m_IndexToCommand.end() )
{
switch( (*itFind) )
{
case pmiHello: doHello(); break;
case pmiThis: doThis(); break;
case pmiIsA: doIsA(); break;
case pmiTest: doTest(); break;
}
}
Now it no longer matters if an item is not added to the menu. As long as the table is updated - I'm happy.