[MonoDevelop] Ideas for a new command system
Rafael Teixeira
Rafael Teixeira <monoman@gmail.com>
Sun, 10 Apr 2005 00:04:24 -0300
Looks very nice. Just performance-wise I would be carefull to
transform the attributes metadata into some indexed form when first
scanning for command handlers to avoid repetitive reflection costs...
May be a premature optimization, but I can't help thinking it will
effectively be needed to attain adequate UI responsiveness.
Have fun,
On Apr 8, 2005 9:22 PM, Lluis Sanchez <lluis@ximian.com> wrote:
> Hi!
>
> The next target in my quest for improving the architecture of MD is the
> command system. There are two reasons why I don't like the current
> design:
>
> * It is not possible to change the behavior of a command depending
> on the context in which it is run. For example, the Delete
> command deletes the selected text in the editor, but we should
> be able to use the same command for deleting the selected file
> in the solution pad (if the pad has the focus), or whatever. Any
> addin should be able to provide a custom behavior for an
> existing command.
> * It is not easy to handle the status of commands. Commands can be
> enabled/disabled using conditions, but conditions must be
> specified in the addin XML file and are very limited.
>
> What I propose is a very different approach, so feedback is greatly
> welcome (BTW, the main concept is taken from MS's MFC class library, not
> a great library, but I like the approach it uses for command handling).
>
> First of all, there is a global list of commands, which is independent
> from where those commands are used. The command list would be
> defined/extended in the addin xml like this:
>
> <Extension path = "/SharpDevelop/Commands">
> <Command id = "EditCommands.Copy"
> _label = "Copy"
> icon = "Icons.16x16.CopyIcon"
> shortcut = "Control|C"/>
> <Command id = "EditCommands.Paste"
> _label = "_Paste"
> icon = "Icons.16x16.PasteIcon"
> shortcut = "Control|V"/>
> <Command id = "EditCommands.Delete"
> _label = "_Delete"
> icon = "Icons.16x16.DeleteIcon"
> shortcut = "Del"/>
> </Extension>
>
> Then, we can define menus and toolbars by refering those commands:
>
> <Extension path =
> "/SharpDevelop/Views/ProjectBrowser/ContextMenu/ProjectFileNode">
> <MenuItem id = "Copy" command = "EditCommands.Copy"/>
> <MenuItem id = "Paste" command = "EditCommands.Paste"/>
> <MenuItem id = "Delete" command = "EditCommands.Delete"/>
> </Extension>
>
> The big change is how commands are executed. Instead of implementing a
> single class for each command, we can implement command handler methods
> in any class. For example, to handle the Delete command in the text
> editor I would write a handler like this:
>
> [CommandHandler (EditCommands.Delete)]
> void OnDeleteCommand ()
> {
> // Delete the selection
> }
>
> If we want to implement the Delete command in a custom pad, we would add
> a similar command handler in that pad. So, we have two handlers for the
> same command in two different classes. Which one of them will be
> executed when clicking on the Delete menu item? It depends on the
> context.
>
> When the command is clicked, the command manager looks for a command
> handler by following a command route. This route begins at the widget
> that has the focus and goes up in the parent chain. This means that if
> we are editing some text in the editor, the delete command handler in
> the editor will be executed. If we move the focus to the solution pad,
> then the pad will get the commands.
>
> The command manager will also automatically disable or hide commands for
> which there isn't a handler in the active command route. This gives a
> lot a consistency to the menu and toolbars, since options and buttons
> will be grayed out when they can't be used (and there is no need to
> write code for this, it comes for free).
>
> If the status of a command depends on some internal logic, we can
> implement that logic in some special command update handlers. For
> example:
>
> [CommandUpdateHandler (EditCommands.Delete)]
> void OnUpdateDeleteCommand (CommandInfo commandInfo)
> {
> if (the_selected_tree_node_can_be_deleted()) {
> commandInfo.Enabled = true;
> commandInfo.Text = "Delete " + current_node.Name;
> } else {
> commandInfo.Enabled = false;
> }
> }
>
> The command manager will look for a command update handler in the
> current command route. If found, it will call the handler and will
> update the menu items and buttons linked to that command accordingly. If
> not found, it will disable them.
>
> This is more or less the idea. There are many more details, such as
> being able to customize the command route, defining global command
> handlers for global commands, menu builders for the "Windows" menu list,
> etc., but I just described the fundamental idea.
>
> Comments?
> Lluis.
>
> _______________________________________________
> Monodevelop-list mailing list
> Monodevelop-list@lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/monodevelop-list
>
--
Rafael "Monoman" Teixeira
---------------------------------------
I'm trying to become a "Rosh Gadol" before my own eyes.
See http://www.joelonsoftware.com/items/2004/12/06.html for enlightment.
It hurts!