| Graphical Text Proposal
(Draft) design documents |
![]() |
| Support for Graphical Text Editing |
This document outlines the requirements for textual graphical editing and any known design decision we have chosen.
Last Updated: November 17th 2004
Graphical Text Editing is defined as the editing of text directly in a Graphical Viewer without the use of native SWT controls such as those used by CellEditors. This is also referred to as WYSIWYG (what-you-see-is-what-you-get) text editing. Such functionality could be used as the basis for editing textual nodes (i.e. sticky notes) in a diagram, building an HTML editor, or even a new form of java source editor. The major concerns include navigation and placement of the Caret, enhancements to Commands and the CommandStack, Selection of text, accessibility, and bidirectional languages (BiDi). The initial phase will concentrate on getting the editing infrastructure right, and not on enhancing the figures and layouts in draw2d to render complex documents.
Defining Textual Selection
|
The notion of selection will be extended to support a single range of selected "characters". Object-based selection will still exist and will coincide with textual selection range. Listeners of selection service will receive some new ISelection derivative which can be queried for both the object selection or textual selection. Simple Selection Range Simple selection can be represented by the EditPart which owns the text selection, and a starting and ending offset index. |
|
|||
| Defining a Textual EditPart The EditPart interface allows the viewer to set the selection state on the part. In a similar way for text support, a textual EditPart will allow the viewer to tell it its "selection range" in the text sense. EditParts are told of their selection state so that it may be rendered correctly in the UI. Extended Selection Range Complex selection can be defined by a pointer to the
starting and ending EditParts, and an offset within each. The
selection range must be contiguous, so all textual elements between the
start and the end are also implicitly selected. This most likely
means that the leaf-node parts are selected. But there may be
applications where selection offsets are inside a container part.
|
||||
|
Figure 2 - Extended selection across multiple parts
|
||||
Keyboard navigation will occur by asking the caret owner for the next caret placement. The presence of a SHIFT modifier will determine whether the existing selection is modified or replaced.
The following table shows some of the strategies for determining the next location.
| Inline | Inline Containers | Blocks | |
| LEFT, RIGHT | local search, then parent | check sibling, then parent | check sibling, then parent |
| UP, DOWN | ask parent | ask parent | ordered search, compare multiple results |
| UP_INTO, DOWN_INTO | local search | local child search, compare multiple results | local child search, compare multiple results |
| HOME_QUERY, END_QUERY | local search | first successful child | first successful child |
| HOME, END | ask parent | ask parent |
ordered search, compare multiple results |
Commands must be used to modify the model.
Typing multiple characters is considered a single edit by the user, and should be undoable via a single invoke of Undo.
Pressing backspace or delete multiple times is considered a single edit by the user. The removal should be undoable via a single invoke of Undo.
Undo and Redo of edits must also place the selection and caret and selection range to the area of the undo/redo. Also, the viewer must be scrolled some amount to expose the maximum of that range.
Processing of editing must be context aware. Different editparts may allow different forms of editing.
Delete, Backspace, and inserting when there is a selection range are all special types of removes. In these cases, the selection range is removed from the model, and the contents following the selection range should be re-parented and even merged into the contents preceding the selection range. When merging is not possible, the Caret is left with the preceding element.
Any edit may return a pending state which is to be applied to a subsequent typing text. For example, If you have a bold word, and you delete it using backspace and then type again, the text should be bold. However, if you delete it and commit that edition, then the empty bold editpart should not exist. Such a pending state is application-specific.
Pending states may also be caused by invoking toolbar or keyboard Actions. For example, pressing CTRL+B should enter a pending "bold" state. Any characters typed should be inserted with bold attributes. But if not text is typed, the model should not be changed.
Commands will be obtained from one target EditPart. The target editpart will be calculated based on the start and end EditParts of the viewer's current Selection Range. The candidate target will be the common ancestor of the start and end parts. If the start and end are the same, then the common ancestor is that part. The candidate will then be asked for the target editpart for the current request, and it may return itself. However, it will often return the outer-most context in which it resides, such as a block of text, a cell inside a table, the "body" of the document, etc.
As the user continues to type, delete, or press backspace, the command which made the initial edit will be updated. An initial request will be sent which contains the current selection range, and the key which was typed. The editpart will return a command for the modification to the model. That command will be executed on the command stack. Upon subsequent editions of the same type, the target editpart will receive another request for a command, but this request will contain the previously executed command. If the editpart wishes to continue the same edit, it must append to this command instance any new editing, and return that same command. Otherwise it may return a different command instance which will be executed normally.
A reused command will implement a special interface allowing it to be executed multiple times by the text tool. When the command is appended, it should not change its undo/redo behavior until this addition has been committed by calling some type of "re-execute" API.
When the user removes the selection range (either via DEL, BACKSPACE, or typing), there are several steps to processing the removal. First, the viewer indicates to all of the textual editparts between the start and end of the selection range that they are selected. This is done so that selection may be rendered in each editpart's figure. This is shown in Figure 3.
Figure 3 - The text viewer and its indicated selection
However, the selected parts are not necessarily all that is removed. If all of the text parts inside a compound part are selected, then that compound parts should be deleted, as shown in Figure 4.
Figure 4 - EditPart structure showing what needs to be deleted
Once the appropriate objects to remove are identified, the application should attempt to merge the text which immediately preceded and followed the selection range. Merging can be complex, but it is important to follow existing conventions whenever possible.
Figure 5 - Intermediate structure after selection range removal
Figure 5 shows the intermediate results after the removal but prior to a possible merge. The preceding and succeeding elements should be merged whenever possible. For example, if both parents represent a paragraph, and the children are text with identical styles, then the two remaining portions should be joined together as shown in Figure 6.1. It would be incorrect to leave the two paragraphs separated. The operation should be equivalent to deleting the ranges from each paragraph, and then placing the caret at the end location and pressing BACKSPACE, which would join the two paragraphs. If both parents are paragraphs, but the children are text with different styles, then the end child is re-parented to the first paragraph, and the second paragraph is removed from the document. This is shown in Figure 6.2. Finally, if the two parents represent styles which are applied to their children, then those styles should remain intact. For example, if the first child were parented by a bold style, and the second child's parent indicated a blue foreground, then this style structure should be maintained, as shown in Figure 6.3. In all 3 cases, the final location for the caret will be where the selection range began. It does not matter if the user selected the range in a forward or backward direction.
Figure 6 - Final structure and caret placement if merging occurs
As the user presses backspace repeatedly, text will get removed from the current selection part until that part has no more text to be deleted. At which point, that text node is empty and probably has no effect on the rendering of the document. The model should be compacted to its simplest representation. But, the application does not know the users intentions. The user may either start typing immediately, or save the document. If the document is saved, it should be in its simplest form. But, if the user inserts a character, the node which became empty should be restored and the character should be placed back into that node. For this to work, we will probably need some pending state object returned from the backspace operation. That state will affect how an inserted character is treated. Several actions will cause the pending state to be thrown out, such as the selection range changing.
Styles are things like Bold, font name, Italic, Underline, or even style "classes" such as H1, etc. Sometimes invoking a style change has an immediate affect on the document. Other times, it has a pending effect which is committed if the user inserts text normally.
When selection is empty, a style change may have a pending effect. For example, turning on BOLD does not modify the document until you type something. Similar for setting font height or name, colors, etc.
When selection is empty, a style change may also have an immediate effect.
When selection exists, a style change must cause an immediate change in the document or do nothing.
It should be possible to display a style value in a read-only way. For example, a locked region of a document is BOLD.
Because of number 2. above, things like paragraph alignment could optionally be implemented as a style. However, generally changing paragraph alignment always has an immediate effect on the document, so it could be just a simple selection-based action.
[Placing the caret with the mouse, selecting with the mouse, dragging selected text, etc].
Using the logic editor as an example, it should be possible to edit a label object without celleditors. F2 or 2 mouse clicks should cause the text editing to become active. Focus lost, Selection lost, or CTRL+ENTER must exit the mode and commit the change. ESC must rollback all text edits and exit the text editing mode.