2. Making a command repeatable and recordable

The following constructor, which invokes the CommandBase constructor, declares command InsertCharByCodeCmd as being repeatable an recordable (using the macro-recorder, that is, ToolsRecord MacroStart Recording in XMLmind XML Editor - Online Help, Stop Recording, Replay Macro).

public InsertCharByCodeCmd() {
    super(/*repeatable*/ true, /*recordable*/ true);
}

A rule of thumb suggests that:

Command InsertCharByCodeCmd could have simply returned CommandResult.DONE. In such case, a user pressing Ctrl+A to repeat command InsertCharByCodeCmd or a user replaying a macro containing command InsertCharByCodeCmd would be prompted to specify the Unicode code point of the character to be inserted. That's not what we want.

In order to achieve what we want, Command InsertCharByCodeCmd must return a CommandResult specifying how to repeat the command and how to replay a macro containing the command without asking anything to the user. This is done by converting the Unicode code point typed by the user in the dialog box to a directly usable command parameter and by adding this “how to repeat me parameter” to the information conveyed by the returned CommandResult.

return CommandResult.success(null,
                             "U+" + Integer.toString((char) code, 16),
                             title);

Convenience method CommandResult.success, which is equivalent to new CommandResult(Status.DONE, result_value, repeat_me_parameter, repeat_me_description), may be used to do this.

[Warning]Pitfall

Many commands change the text or node selection at the very end of their doExecute method. Some commands, like copy, explicitly invoke MarkManager.notifyContextChangeListeners. Both these actions trigger an ContextChangeEvent.

In such case, always invoke CommandResult.success in order to initialize the CommandResult which will be returned by the command before changing the editing context of the document. For example:

...
CommandResult result =
    CommandResult.success(null, makeParameter(parameter, newName),
                          title);

markManager.remove(Mark.SELECTED2);
markManager.remove(Mark.MARK);
markManager.set(Mark.SELECTED, element);
docView.ensureDotIsInside(element);
markManager.endMark();

return result;

The reason of this pitfall is a design flaw in XXE v10 commands:

  • any change to the editing context (typically the text or node selection changes) causes the prepare method of command repeat in XMLmind XML Editor - Commands to be invoked

    • which causes the prepare method of last repeatable command (the command we are talking about) to be invoked

      • which causes the internal state of this command to be modified.

        The problem is that this internal state (instance variable code in the above example) is almost always needed in order to use CommandResult.success.