/// <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); }
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); } }
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); }
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); }
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!"); } } } }