1. The prepare and execute methods

Client code wanting to test whether a command can be executed given current DocumentView context will just invoke method prepare:

if (cmd.prepare(docView, param, x, y)) {
    // Do something, for example enable a button or a menu item.
}

Client code wanting to actually execute a command will invoke the prepare and execute methods as follows:

if (cmd.prepare(docView, param, x, y)) {
    cmd.execute(docView, param, x, y);
}
[Important]

You can safely assume that method execute will never be invoked without being immediately preceded by an invocation of method prepare returning true (with exactly the same arguments as those passed to execute).

Therefore these methods may be informally described as follows:

prepare

Examines the context of the invocation: the node clicked upon (if arguments xy have been specified), implicitly or explicitly selected nodes, the contents of the clipboard, etc.

If the command cannot be executed in this context, this method returns false.

If the command can be executed in this context, this method returns true. In such case, most commands update their internal state in order to facilitate the job of possibly following method execute.

Method prepare may be called quite often. For example, each time the selection implicitly or explicitly changes in current DocumentView, the prepare methods of the commands bound to XXE menu items and toolbar buttons are invoked. That's dozens of invocations at a time.Therefore,

  • Method prepare must be as quick as possible,

  • Method prepare may not report any information of any kind (even an error; silently return false in such case) and may not log any information of any kind.

execute

Really does the job. Assumes that method prepare has just returned true.

Method execute may be interactive. It may display dialog boxes prompting the user for some information. It may report error using alert dialog boxes, for example Alert.showError. It may display status message using DocumentView.showStatus.

Method execute returns a CommandResult. In its simplest form, a CommandResult is just the status of the command execution:

CommandResult.STOPPED

Equivalent to new CommandResult(Status.STOPPED, null, null). The execution has been stopped because the command needs to display a dialog box and the computer on which the command runs has no display. Not useful unless you intend to run your command in XMLmind XML Editor Web Edition. More information below.

CommandResult.CANCELED

Equivalent to new CommandResult(Status.CANCELED, null, null). The command execution has been canceled by the user.

CommandResult.FAILED

Equivalent to new CommandResult(Status.FAILED, null, null). The command execution has failed.

CommandResult.DONE

Equivalent to new CommandResult(Status.DONE, null, null). The command execution has succeeded and the command did not return any meaningful value as its result.

Convenience method CommandResult.done(Object value) may be be used to specify the result —an object of any kind, this depends entirely on the command— of a successful execution.

[Important]Is it execute or doExecute?

Method execute of course ends up invoking method doExecute.

A third-party developer must always implement abstract method doExecute and not method execute. For a third-party developer, there is no need to override method execute.

Methods prepare, execute (and doExecute) have exactly the same parameters:

DocumentView docView

The DocumentView on which the command is acting.

String parameter

This string parametrizes the behavior of the command. Each command has its own syntax for its parameter string. Commands which cannot be parametrized must be passed null (null may be also accepted by some commands which can be parametrized). See Chapter 6, Commands written in the Java™ programming language in XMLmind XML Editor - Commands for a complete description of available commands and their parameters.

int x, y

Some commands are designed to be bound to a mouse input. These arguments are the coordinates, in the DocumentView coordinate system, of mouse input which triggered the command. For the other type of commands, designed to be bound to a keyboard input or to be invoked from a menu, these coordinates are set to -1.

1.1. A very simple, sample command

Let's use a very simple command, InsertCharByCodeCmd, to illustrate all this. Sample command InsertCharByCodeCmd inserts a character specified using its Unicode code point at caret location.

Excerpts from InsertCharByCodeCmd.java:

public class InsertCharByCodeCmd extends CommandBase {
    private int code;1

    public InsertCharByCodeCmd() {
        super(/*repeatable*/ true, /*recordable*/ true);2
    }
    
    public boolean prepare(DocumentView docView, 
                           String parameter, int x, int y) {
        if (!docView.canInsertString()) {
            return false;
        }
        
        code = 0;
        if (parameter != null) {
            code = parseUnicode(parameter);
            if (code <= 0) {3
                return false;
            }
        }

        return true;
    }

1

Instance variable code is the “internal state” of this command. Initialized in method prepare. Used by method doExecute.

[Note]About the “internal state” of a command

Instance variables of a command are like the local variables of a function. They are set by method prepare in order to be used in possibly following method execute and after that, they are completely forgotten about.

2

More about this constructor in next section.

3

Specified parameter cannot be parsed as a Unicode code point. Notice that no error is reported to the user. The method simply returns false.

    public CommandResult doExecute(DocumentView docView, 
                                   String parameter, int x, int y) {
        String title = "INSERT CHARACTER BY CODE";

        if (code <= 0) {
            Component dialogParent = docView.getDialogParent();
            if (dialogParent == null) {1
                return CommandResult.STOPPED;
            }

            PromptDialog prompt =
                new PromptDialog(dialogParent, 20,2
                                 /*browseButton*/ false, /*helpButton*/ false);
            String value =
                prompt.getValue(title,
                                "Unicode character" +
                                " (example \"U+2022\" for \"BULLET\"):",
                                /*value*/ "", /*baseURL*/ null,
                                /*allowAnyString*/ true);
            if (value == null ||
                (value = value.trim()).length() == 0) {
                //docView.showStatus("Command canceled by user.");
                return CommandResult.CANCELED;3
            }
            
            code = parseUnicode(value);
            if (code <= 0 ||
                !XMLText.isXMLChar((char) code)) {
                Alert.showError(dialogParent,
                                "Cannot parse \"" + value +
                                "\" as an XML character.");
                return CommandResult.FAILED;4
            }
        }

        docView.insertString(Character.toString((char) code),
                             docView.getOverwriteMode());5
        
        return CommandResult.success(null,6
                                     "U+" + Integer.toString((char) code, 16),
                                     title);
    }

1

This test is optional. The parent component of a dialog box is obtained using DocumentView.getDialogParent and docView.getDialogParent() never returns null unless InsertCharByCodeCmd is invoked by xxeserver, the server side part of XMLmind XML Editor Web Edition[3].

2

Which character is to be inserted is not specified by param, so ask the user.

3

User clicked button Cancel, so stop the execution there by returning CommandResult.CANCELED.

Though not useful in such case, docView.showStatus("Command canceled by user.") could have been used to clearly indicate that the command has been canceled and this, without displaying an alert dialog box.

4

The user has typed a string which cannot be parsed as a usable character, so stop the execution there by returning CommandResult.FAILED after displaying an error dialog box.

5

Insert specified character at caret location using DocumentView.insertString.

6

This command could also have returned CommandResult.DONE. More about CommandResult.success in next section.



[3] xxeserver is designed to run on computers having no display (xxeserver is started with -Djava.awt.headless=true) therefore docView.getDialogParent() returns null.