Complex, complicated, elaborate, difficult, Byzantine, labyrinthine. Bewildering. The opposite of simple is wrong. Putting in this simple and common operation, inserting some XML tags, required me to change code in a number of places. The places were not all obvious, and changes were required all over the code, in more than one source file. This is nature s way of telling us that we have screwed up.
Moving along here, involved in the book, perhaps you have been dragged along in my wake, with the feeling that each change has made sense and with a general feeling that you understand how the menus work. Or, perhaps, you have felt a growing feeling that this isn t right. That has been my own situation: I have been going along feeling that everything is OK and we can easily enough add new things, yet with a growing feeling that this can t be right. That s good. We stick with what we have and what we know while it serves us, and we remain open to learning that it isn t good enough. Today, facing making several changes like this one, we see that this just isn t right. If you re like me, you re not even sure you could write down what has to be done to add a tag- inserting menu item. With the help of the code, let s make that list:
Declare a MenuItem member variable, and initialize it:
private MenuItem insertUnorderedList;
...
private void initialize(TextModel model) {
...
insertUnorderedList = new MenuItem (
"Insert &UL",
new EventHandler(MenuInsertUnorderedList));
...
}
Implement the EventHandler referred to in the MenuItem:
void MenuInsertUnorderedList(object obj, EventArgs ea) {
CallModel(insertUnorderedListAction);
}
Declare the ModelAction variable referred to in the EventHandler, and initialize it:
private ModelAction insertUnorderedListAction;
...
private void InitializeDelegates(TextModel model) {
enterAction = new ModelAction(model.Enter);
shiftEnterAction = new ModelAction(model.InsertReturn);
insertSectionAction = new ModelAction(model.InsertSectionTags);
insertPreTagAction = new ModelAction(model.InsertPreTag);
insertUnorderedListAction = new ModelAction(model.InsertUnorderedList); saveAction = new ModelAct ion(this.SaveFile);
loadAction = new ModelAction(this.LoadFile);
}
Implement, in the TextModel class, the insert method referred to in the ModelAction:
public void InsertUnorderedList() {
InsertTags(newUnorderedList, unorderedListSkip);
}
Define the tag lists referred to in the insert method:
private static string[] newUnorderedList = {"<UL>","<LI></LI>","</UL>"};
private static string[] unorderedListSkip = { "<UL>", "<LI>" };
Oh, and I almost forgot : change the menu search logic, back in the XML Notepad, to find the new menu:
public MenuItem MenuForAccelerator(string accelerator) {
if (accelerator == "&S") return insertSection;
if (accelerator == "&P") return insertPre;
if (accelerator == " & U") return insertUnorderedList;
if (accelerator == "^O") return openFile;
if (accelerator == "^S") return saveFile;
return null;
}
Even now, I m not sure that I have them all. Wait ”and I really did forget this until now ”we have to do another thing: we have to add our menu item to the main menu:
this.Menu = new MainMenu(new MenuItem[]
{fileMenu, insertPre, insertSection, insertUnorderedList } );
No wonder we re confused . No wonder it always takes us a few extra tests to get a new menu item right. And imagine how difficult it s going to be for some other programmer to come along and install a new insertion item. She might be able to follow along, one step at a time, starting from an existing MenuItem, but she is almost certain to miss the menu search logic and she might well miss the addition of her new menu to the main menu. This isn t good.