/// <summary>
        /// Inserts the specified text at the current cursor position, if possible
        /// </summary>
        private async Task InsertText(XmlCursor cursor, string text, XmlRules xmlRules)
        {
            XmlCursorPos insertPos;

            // If something is selected, then delete it first, because it will be replaced by the new text
            XmlCursor deleteArea = cursor.Clone();
            await deleteArea.OptimizeSelection();

            var deleteResult = await XmlCursorSelectionHelper.DeleteSelection(deleteArea);

            if (deleteResult.Success)
            {
                insertPos = deleteResult.NewCursorPosAfterDelete;
            }
            else
            {
                insertPos = cursor.StartPos.Clone();
            }

            // insert the specified text at the cursor position
            var replacementNode = InsertAtCursorPosHelper.InsertText(insertPos, text, xmlRules).ReplaceNode;

            if (replacementNode != null)
            {
                // Text could not be inserted because a node input was converted from text input.
                // Example: In the AIML template, * is pressed, and a <star> is inserted there instead
                InsertAtCursorPosHelper.InsertXmlNode(insertPos, replacementNode, xmlRules, false);
            }

            // then the cursor is only one line behind the inserted text
            await cursor.SetPositions(insertPos.ActualNode, insertPos.PosOnNode, insertPos.PosInTextNode, throwChangedEventWhenValuesChanged : false);
        }
Example #2
0
 public KeyboardHandler(EditorContext editorContext)
 {
     this.actions        = editorContext.Actions;
     this.editorState    = editorContext.EditorState;
     this.xmlRules       = editorContext.XmlRules;
     this.nativePlatform = editorContext.NativePlatform;
     this.nativePlatform.InputEvents.PreviewKey.Add(this.ControlKeyPreview);
 }
        /// <summary>
        /// FInserts the specified node at the current cursor position, if possible
        /// </summary>
        private async Task XMLNodeEinfuegen(XmlCursor cursor, XmlNode node, XmlRules xmlRules, bool setNewCursorPosBehindNewInsertedNode)
        {
            // If something is selected, then delete it first, because it will be replaced by the new text
            XmlCursor deleteArea = cursor.Clone();
            await deleteArea.OptimizeSelection();

            var deleteResult = await XmlCursorSelectionHelper.DeleteSelection(deleteArea);

            if (deleteResult.Success)
            {
                await cursor.SetPositions(deleteResult.NewCursorPosAfterDelete.ActualNode, deleteResult.NewCursorPosAfterDelete.PosOnNode, deleteResult.NewCursorPosAfterDelete.PosInTextNode, throwChangedEventWhenValuesChanged : false);
            }

            // insert the specified node at the cursor position
            if (InsertAtCursorPosHelper.InsertXmlNode(cursor.StartPos, node, xmlRules, setNewCursorPosBehindNewInsertedNode))
            {
                // then the cursor is only one line behind the inserted
                cursor.EndPos.SetPos(cursor.StartPos.ActualNode, cursor.StartPos.PosOnNode, cursor.StartPos.PosInTextNode);
            }
        }
Example #4
0
        internal static async Task <bool> MoveLeft(XmlCursorPos cursorPos, System.Xml.XmlNode rootnode, XmlRules xmlRules)
        {
            var actualNode = cursorPos.ActualNode;

            switch (cursorPos.PosOnNode)
            {
            case XmlCursorPositions.CursorOnNodeStartTag:
            case XmlCursorPositions.CursorOnNodeEndTag:
                cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                break;

            case XmlCursorPositions.CursorInFrontOfNode:
                if (actualNode != rootnode)
                {
                    if (actualNode.PreviousSibling != null)
                    {
                        cursorPos.SetPos(actualNode.PreviousSibling, XmlCursorPositions.CursorBehindTheNode);
                        await MoveLeft(cursorPos, rootnode, xmlRules);
                    }
                    else     // no previous sibling node available
                    {
                        cursorPos.SetPos(actualNode.ParentNode, XmlCursorPositions.CursorInFrontOfNode);
                    }
                }
                else
                {
                    return(false);
                }
                break;

            case XmlCursorPositions.CursorBehindTheNode:
                if (ToolboxXml.IsTextOrCommentNode(actualNode))     // With a text node the cursor is placed behind the last character
                {
                    cursorPos.SetPos(actualNode, XmlCursorPositions.CursorInsideTextNode, Math.Max(0, ToolboxXml.TextFromNodeCleaned(actualNode).Length - 1));
                }
                else
                {
                    if (actualNode.ChildNodes.Count == 0)
                    {
                        if (xmlRules.HasEndTag(actualNode))
                        {
                            //  If the cursor shows a close tag, place it in the empty node
                            cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInsideTheEmptyNode);
                        }
                        else
                        {
                            // If the cursor does *not* show a close tag, place it before the empty node
                            cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                        }
                    }
                    else     // there are children in the node
                    {
                        cursorPos.SetPos(actualNode.LastChild, XmlCursorPositions.CursorBehindTheNode);
                    }
                }
                break;

            case XmlCursorPositions.CursorInsideTheEmptyNode:
                cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                break;

            case XmlCursorPositions.CursorInsideTextNode:
                if (ToolboxXml.IsTextOrCommentNode(actualNode))     // Node is text node
                {
                    if (cursorPos.PosInTextNode > 1)
                    {      // Cursor one character to the left
                        cursorPos.SetPos(cursorPos.ActualNode, cursorPos.PosOnNode, cursorPos.PosInTextNode - 1);
                    }
                    else
                    {
                        // Put in front of the node
                        cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                    }
                }
                else     // not a text node
                {
                    throw new ApplicationException(string.Format("XMLCursorPos.MoveLeft: CursorPos is XMLCursorPositions.CursorInsideTextNodes, but no text node is selected, but the node {0}", actualNode.OuterXml));
                }
                break;

            default:
                throw new ApplicationException(String.Format("XMLCursorPos.MoveLeft: unknown CursorPos {0}", cursorPos.PosOnNode));
            }
            return(true);
        }
Example #5
0
        internal static async Task <bool> MoveRight(XmlCursorPos cursorPos, System.Xml.XmlNode rootnode, XmlRules xmlRules)
        {
            System.Xml.XmlNode node = cursorPos.ActualNode;

            switch (cursorPos.PosOnNode)
            {
            case XmlCursorPositions.CursorOnNodeStartTag:
            case XmlCursorPositions.CursorOnNodeEndTag:
                cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                break;

            case XmlCursorPositions.CursorBehindTheNode:
                if (node.NextSibling != null)
                {
                    // Place in front of the next sibling
                    cursorPos.SetPos(node.NextSibling, XmlCursorPositions.CursorInFrontOfNode);
                    // Since "behind the first" looks the same as "before the second", move one more step to the right
                    await MoveRight(cursorPos, rootnode, xmlRules);
                }
                else     // No following siblings available, then set behind the parent node
                {
                    if (node.ParentNode != rootnode)
                    {
                        cursorPos.SetPos(node.ParentNode, XmlCursorPositions.CursorBehindTheNode);
                        if (!xmlRules.HasEndTag(node.ParentNode))
                        {     // If no closed tag is displayed for the parent, then one more to the right
                            await MoveRight(cursorPos, rootnode, xmlRules);
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                break;

            case XmlCursorPositions.CursorInsideTheEmptyNode:
                cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                break;

            case XmlCursorPositions.CursorInFrontOfNode:
                if (ToolboxXml.IsTextOrCommentNode(node))                                                   // The node itself is text node
                {
                    if (ToolboxXml.TextFromNodeCleaned(node).Length > 1)                                    // Text node is not empty
                    {
                        cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInsideTextNode, 1); // one character forward, i.e. after the first character
                    }
                    else                                                                                    // Text node is empty
                    {
                        cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                    }
                }
                else      // Node is not a text node
                {
                    if (node.ChildNodes.Count == 0)
                    {
                        if (!xmlRules.HasEndTag(node))     // If no closed tag is displayed for this node, then directly behind the node
                        {
                            cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                        }
                        else      // Node has closing tag, so put it in between
                        {
                            // Set to the empty node
                            cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorInsideTheEmptyNode);
                        }
                    }
                    else     // Children available
                    {
                        cursorPos.SetPos(node.FirstChild, XmlCursorPositions.CursorInFrontOfNode);
                    }
                }
                break;

            case XmlCursorPositions.CursorInsideTextNode:
                if (ToolboxXml.IsTextOrCommentNode(node))                                          // Node is text node
                {
                    if (ToolboxXml.TextFromNodeCleaned(node).Length > cursorPos.PosInTextNode + 1) // there is text in the text node on the right
                    {
                        // one character forward, i.e. after the first character
                        cursorPos.SetPos(cursorPos.ActualNode, cursorPos.PosOnNode, cursorPos.PosInTextNode + 1);

                        /*if ((XMLEditor.TextAusTextNodeBereinigt(node).Length == cursor.PosInNode) && (node.NextSibling != null))
                         * {
                         *  // If after the last drawing of the text node and following sibling exists, then before the following sibling node
                         * }*/
                    }
                    else      // no text follows in the text node
                    {
                        cursorPos.SetPos(cursorPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                    }
                }
                else     // Node is not a text node
                {
                    throw new ApplicationException(String.Format("XMLCurorPos.MoveRight: CursorPos is XMLCursorPositions.CursorInsideTextNodes, but no text node is selected, but the node {0}", node.OuterXml));
                }
                break;

            default:
                throw new ApplicationException(String.Format("XMLCurorPos.MoveRight: unknown CursorPos {0}", cursorPos.PosOnNode));
            }
            return(true);
        }
Example #6
0
 public EditorContext(EditorConfig editorConfig, XmlRules xmlRules) : this(editorConfig)
 {
     this.XmlRules = xmlRules;
 }
        /// <summary>
        /// Inserts the specified XML node at the specified position
        /// </summary>
        internal static bool InsertXmlNode(XmlCursorPos cursorPos, System.Xml.XmlNode node, XmlRules xmlRules, bool setNewCursorPosBehindNewInsertedNode)
        {
            System.Xml.XmlNode parentNode = cursorPos.ActualNode.ParentNode;

            switch (cursorPos.PosOnNode)
            {
            case XmlCursorPositions.CursorOnNodeStartTag:     // replace the acual node
            case XmlCursorPositions.CursorOnNodeEndTag:
                parentNode.ReplaceChild(node, cursorPos.ActualNode);
                break;

            case XmlCursorPositions.CursorInFrontOfNode:     // insert before actual node
                parentNode.InsertBefore(node, cursorPos.ActualNode);
                break;

            case XmlCursorPositions.CursorBehindTheNode:     // insert after actual node
                parentNode.InsertAfter(node, cursorPos.ActualNode);
                break;

            case XmlCursorPositions.CursorInsideTheEmptyNode:     // insert into empty node
                cursorPos.ActualNode.AppendChild(node);
                break;

            case XmlCursorPositions.CursorInsideTextNode:     // insert into textnode

                // Make the text available as a node before the insertion position
                string             textDavor     = cursorPos.ActualNode.InnerText.Substring(0, cursorPos.PosInTextNode);
                System.Xml.XmlNode textDavorNode = parentNode.OwnerDocument.CreateTextNode(textDavor);

                // Provide the text behind the insert position as a node
                string             textAfter     = cursorPos.ActualNode.InnerText.Substring(cursorPos.PosInTextNode, cursorPos.ActualNode.InnerText.Length - cursorPos.PosInTextNode);
                System.Xml.XmlNode textAfterNode = parentNode.OwnerDocument.CreateTextNode(textAfter);

                // Insert the node to be inserted between the new before and after text node
                // -> so replace the old text node with
                // textbefore - newNode - textafter
                parentNode.ReplaceChild(textDavorNode, cursorPos.ActualNode);
                parentNode.InsertAfter(node, textDavorNode);
                parentNode.InsertAfter(textAfterNode, node);
                break;

            default:
                throw new ApplicationException(String.Format("InsertXmlNode: unknown PosOnNode {0}", cursorPos.PosOnNode));
            }

            // set cursor
            if (setNewCursorPosBehindNewInsertedNode)
            {
                // Place cursor behind the new node
                cursorPos.SetPos(node, XmlCursorPositions.CursorBehindTheNode);
            }
            else
            {
                if (xmlRules.HasEndTag(node))
                {
                    // Place cursor in the new node
                    cursorPos.SetPos(node, XmlCursorPositions.CursorInsideTheEmptyNode);
                }
                else
                {
                    // Place cursor behind the new node
                    cursorPos.SetPos(node, XmlCursorPositions.CursorBehindTheNode);
                }
            }
            return(true);
        }
        /// <summary>
        /// Inserts the specified text at the current cursor position, if possible
        /// </summary>
        internal static InsertTextResult InsertText(XmlCursorPos cursorPos, string rawText, XmlRules xmlRules)
        {
            // Revise the entered text in preprocessing if necessary.
            // In an AIML 1.1 DTD this can mean, for example, that the text for insertion into the PATTERN tag is changed to upper case
            string text = xmlRules.InsertTextTextPreProcessing(rawText, cursorPos, out System.Xml.XmlNode replacementNode);

            if (replacementNode != null)
            {
                // If the entered text has become a node instead, e.g. with AIML,
                // if you press * in a template and then want to insert a <star> instead
                return(new InsertTextResult {
                    ReplaceNode = replacementNode
                });
            }

            switch (cursorPos.PosOnNode)
            {
            case XmlCursorPositions.CursorOnNodeStartTag:
            case XmlCursorPositions.CursorOnNodeEndTag:
                // First check whether this node may be replaced by a text node
                if (xmlRules.IsThisTagAllowedAtThisPos("#PCDATA", cursorPos))
                {
                    // The selected node by a newly created text node
                    System.Xml.XmlText neuerTextNode = cursorPos.ActualNode.OwnerDocument.CreateTextNode(text);
                    cursorPos.ActualNode.ParentNode.ReplaceChild(cursorPos.ActualNode, neuerTextNode);
                    cursorPos.SetPos(neuerTextNode, XmlCursorPositions.CursorBehindTheNode);
                }
                throw new ApplicationException(String.Format("InsertText: unknown CursorPos {0}", cursorPos.PosOnNode));

            case XmlCursorPositions.CursorBehindTheNode:
                InsertTextBetweenTwoNodes(cursorPos, cursorPos.ActualNode, cursorPos.ActualNode.NextSibling, text, xmlRules);
                break;

            case XmlCursorPositions.CursorInFrontOfNode:
                InsertTextBetweenTwoNodes(cursorPos, cursorPos.ActualNode.PreviousSibling, cursorPos.ActualNode, text, xmlRules);
                break;

            case XmlCursorPositions.CursorInsideTheEmptyNode:
                // First check if text is allowed inside the empty node
                if (xmlRules.IsThisTagAllowedAtThisPos("#PCDATA", cursorPos))
                {
                    // Then create a text node within the empty node with the desired text content
                    System.Xml.XmlText newTextNode = cursorPos.ActualNode.OwnerDocument.CreateTextNode(text);
                    cursorPos.ActualNode.AppendChild(newTextNode);
                    cursorPos.SetPos(newTextNode, XmlCursorPositions.CursorBehindTheNode);
                }
                else
                {
                    // Error BEEEEP!
                }
                break;

            case XmlCursorPositions.CursorInsideTextNode:
                string textBeforeNode  = cursorPos.ActualNode.InnerText.Substring(0, cursorPos.PosInTextNode);
                string textAfterCursor = cursorPos.ActualNode.InnerText.Substring(cursorPos.PosInTextNode, cursorPos.ActualNode.InnerText.Length - cursorPos.PosInTextNode);
                // Insert the character of the pressed keys after the cursor
                cursorPos.ActualNode.InnerText = $"{textBeforeNode}{text}{textAfterCursor}";
                cursorPos.SetPos(cursorPos.ActualNode, cursorPos.PosOnNode, cursorPos.PosInTextNode + text.Length);
                break;

            default:
                throw new ApplicationException(String.Format("InsertText: unknown CursorPos {0}", cursorPos.PosOnNode));
            }
            return(new InsertTextResult {
                ReplaceNode = replacementNode
            });
        }
        /// <summary>
        /// Inserts a text between two nodes
        /// </summary>
        internal static void InsertTextBetweenTwoNodes(XmlCursorPos cursorPos, System.Xml.XmlNode nodeBefore, System.Xml.XmlNode nodeAfter, string text, XmlRules xmlRules)
        {
            if (ToolboxXml.IsTextOrCommentNode(nodeBefore))  // if the node is already text before, then simply append to it
            {
                nodeBefore.InnerText += text;
                cursorPos.SetPos(nodeBefore, XmlCursorPositions.CursorInsideTextNode, nodeBefore.InnerText.Length);
            }
            else  // the node before is no text
            {
                if (ToolboxXml.IsTextOrCommentNode(nodeAfter))  // if the node behind it is already text then just paste it into
                {
                    nodeAfter.InnerText = $"{text}{nodeAfter.InnerText}";
                    cursorPos.SetPos(nodeAfter, XmlCursorPositions.CursorInsideTextNode, text.Length);
                }
                else // the node behind is also no text
                {
                    // Insert between two non-text nodes
                    if (xmlRules.IsThisTagAllowedAtThisPos("#PCDATA", cursorPos))
                    {
                        System.Xml.XmlText newTextNode = cursorPos.ActualNode.OwnerDocument.CreateTextNode(text);
                        InsertXmlNode(cursorPos, newTextNode, xmlRules, false);
                    }
                    else
                    {
#warning Insert another correct message or sound
                        Debug.Assert(false, "Error - Beep!");
                    }
                }
            }
        }