3. Sample command WrapElementCmd

WrapElementCmd “wraps” selected element in a new parent element which is chosen interactively using the element chooser dialog box. This is a simplified version of command wrap in XMLmind XML Editor - Commands.

WrapElementCmd is an example of a validating command.

3.1. How it works

WrapElementCmd wraps explicitly or implicitly selected element in a new parent element. Example:

<blockquote>
  <para>the <emphasis>little</emphasis> girl.</para>
</blockquote>

In the above blockquote, para is implicitly selected because the caret is before word "girl". User chooses to wrap it in a note element, which gives:

<blockquote>
  <note>
    <para>the <emphasis>little</emphasis> girl.</para>
  </note>
<blockquote>

3.1.1. Using an ElementEditor

WrapElementCmd is an example of a validating command, that is, a command which cannot make the document invalid by inserting, deleting or replacing nodes.

This kind of command often requires the user to specify which element is to be inserted in the document. In such case, the chooser dialog box should only display elements which, when inserted in the document, cannot make it invalid.

This kind of command always uses an ElementEditor.

An ElementEditor is a validating editor which operates on the child nodes of a given element.

In order to use an ElementEditor, you need to create it and then to specify which element is being edited:

ElementEditor elementEditor = new ElementEditor(xmlClipboard, docType, null);
elementEditor.setEditedElement(elem);

It implements a number of editing operations: delete, insert, replace, convert, wrap, cut, paste, etc.

For each operation, there are 3 methods:

Validating commands operating on the text selection rather than on the node selection use a TextEditor rather than an ElementEditor.

3.2. First step: prepare

Excerpts from WrapElementCmd.java:

public class WrapElementCmd extends CommandBase {
    private Element element;

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

    public boolean prepare(DocumentView docView, 
                           String parameter, int x, int y) {
        element = docView.getSelectedElement(/*implicit*/ true);1
        if (element == null) {
            return false;
        }

        Element editedElement = element.getParentElement();2
        if (editedElement == null) {
            return false;
        }
        ElementEditor elementEditor = docView.getElementEditor();3
        elementEditor.editElement(editedElement);4

        return elementEditor.canWrap(element, element);5
    }

1

WrapElementCmd can be executed only if a single element is implicitly or explicitly selected. getSelectedElement(true) returns this implicitly or explicitly selected element. It returns null if text or multiple nodes are selected.

2

The element being edited is the parent of the selected element.

3

Commands do not need to create ElementEditors or TextEditors. The DocumentView has ready-to-use validating editors. Such editors can be accessed using getElementEditor and getTextEditor.

4

editElement is more efficient than setEditedElement but can only be used with the ElementEditor owned by the DocumentView.

5

Tests if there is at least one parent element which can be used to wrap selected element.

3.3. Second step: doExecute

    public CommandResult doExecute(DocumentView docView, String parameter, 
                                   int x, int y) {
        ElementEditor elementEditor = docView.getElementEditor();1
        Element editedElement = element.getParentElement();

        ArrayList<Field> fieldList = new ArrayList<Field>();
        elementEditor.canWrap(element, element, fieldList);2

        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);

        String title = "WRAP ELEMENT";
        FieldChooserDialog dialog = 
            new FieldChooserDialog(docView.getDialogParent(), title);

        FieldChoice[] choices = 
            FieldChoice.list(fields, /*includingText*/ false, 
                             /*includingWildcards*/ true,
                             /*includingTemplates*/ false, editedElement);3
        FieldChoice choice = dialog.chooseField(choices, editedElement);4
        if (choice == null) {
            return CommandResult.CANCELED;
        }
        
        MarkManager markManager = docView.getMarkManager();
        markManager.beginMark();

        Element wrapper = elementEditor.wrap(element, element,
                                             choice.field, choice.name);5

        docView.describeUndo(title);

        markManager.remove(Mark.MARK);
        markManager.remove(Mark.SELECTED2);
        markManager.set(Mark.SELECTED, wrapper);6
        docView.moveDotInto(wrapper);

        markManager.endMark();

        return CommandResult.DONE;
    }
}

1

There is no need to call editElement(editedElement). Remember that doExecute is never invoked without being preceded by prepare. Therefore the ElementEditor is necessarily properly configured.

2

canWrap fills ArrayList fieldList with all possible Fields.

3

FieldChoice.list is used to create a properly labeled list of choices out of a list of Fields and a context (editedElement).

4

FieldChooserDialog is displayed to let the user specify which element he wants to use to wrap selected element.

This dialog box returns a FieldChoice describing user's choice or null if user has canceled the command.

5

Wraps selected element in a new parent element.

6

Selects the newly created parent element.