Commands.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:76k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Xml;
  3. using System.Windows.Forms;
  4. using System.Collections;
  5. using System.Diagnostics;
  6. using System.Runtime.Serialization;
  7. using System.Text.RegularExpressions;
  8. using System.IO;
  9. using System.Text;
  10. namespace XmlNotepad {
  11.     public enum InsertPosition { Child, Before, After }
  12.     /// <summary>
  13.     /// This class normalizes the concept of parent for XmlTreeNode and XmlNode node.
  14.     /// The reason for this is that XmlTreeNode.Parent returns null on root level nodes and
  15.     /// XmlNode.ParentNode returns null on XmlAttributes. So this class provides one
  16.     /// uniform way to insert and remove both TreeNodes and their associated XmlNodes. 
  17.     /// </summary>
  18.     /// <remarks>MCorning made public so subforms have access.</remarks>
  19.     public class TreeParent {
  20.         //XmlTreeNode node;      // the reference node ("selected" node)
  21.         bool nodeInTree;    // is the reference node in the tree?
  22.         XmlTreeNode parent;
  23.         TreeView view;
  24.         //XmlNode xnode;
  25.         XmlNode xparent;
  26.         XmlNode originalParent;
  27.         XmlDocument doc;
  28.         // There is no reference node, so the parent is the TreeView and XmlDocument.
  29.         public TreeParent(TreeView view, XmlDocument doc) {
  30.             this.view = view;
  31.             this.doc = doc;
  32.             this.xparent = doc;
  33.         }
  34.         public TreeParent(XmlTreeView xview, XmlDocument doc, XmlTreeNode node)
  35.             : this(xview.TreeView, doc, node) {
  36.         }
  37.         
  38.         // This constructor takes the reference node
  39.         public TreeParent(TreeView view, XmlDocument doc, XmlTreeNode node) {
  40.             //this.node = node;
  41.             if (node != null) this.nodeInTree = ((TreeView)node.TreeView == view);
  42.             this.view = view;
  43.             this.doc = doc;
  44.             this.parent = (XmlTreeNode)node.Parent;
  45.  
  46.             //this.xnode = node.Node;
  47.             if (node.Parent != null) {
  48.                 this.xparent = ((XmlTreeNode)node.Parent).Node;
  49.             } else if (node.Node != null) {                
  50.                 this.xparent = node.Node.ParentNode;
  51.             }
  52.             if (this.xparent == null){
  53.                 this.xparent = this.doc;
  54.             }
  55.             originalParent = this.xparent;
  56.             if (this.parent == null) {
  57.                 this.xparent = this.originalParent = this.doc;
  58.             }
  59.         }
  60.         public int Count {
  61.             get {
  62.                 if (parent != null) return parent.Nodes.Count;
  63.                 return view.Nodes.Count;
  64.             }
  65.         }
  66.         public TreeView View {
  67.             get { return this.view; }
  68.         }
  69.         public XmlDocument Document {
  70.             get { return this.doc; }
  71.         }
  72.         public bool IsNodeInTree {
  73.             get { return this.nodeInTree; }
  74.         }
  75.         public XmlTreeNode GetChild(int i) {
  76.             if (parent != null) return (XmlTreeNode)parent.Nodes[i];
  77.             return (XmlTreeNode)view.Nodes[i];
  78.         }
  79.         public void SetParent(XmlTreeNode parent) {
  80.             this.parent = parent;
  81.             if (parent != null && parent.Node != null) {
  82.                 this.SetXmlParent(parent.Node);
  83.             }
  84.         }
  85.         void SetXmlParent(XmlNode parent) {
  86.             if (parent != null) {
  87.                 this.xparent = parent;
  88.                 doc = xparent.OwnerDocument;
  89.             }
  90.         }
  91.         public bool IsRoot {
  92.             get { return xparent == null || xparent is XmlDocument; }
  93.         }
  94.         public bool IsElement {
  95.             get { return xparent is XmlElement; }
  96.         }
  97.         public XmlNode ParentNode {
  98.             get { return this.xparent; }
  99.         }
  100.         public int AttributeCount {
  101.             get {
  102.                 if (xparent == null || xparent.Attributes == null) return 0;
  103.                 return xparent.Attributes.Count;
  104.             }
  105.         }
  106.         public int ChildCount {
  107.             get {
  108.                 if (xparent != null && xparent.HasChildNodes)
  109.                     return xparent.ChildNodes.Count;
  110.                 return 0;
  111.             }
  112.         }
  113.         public void Insert(int pos, InsertPosition position, XmlTreeNode n, bool selectIt) {
  114.             
  115.             if (n.Node != null) {
  116.                 this.Insert(pos, position, n.Node);
  117.             }
  118.             
  119.             int i = pos;
  120.             if (position == InsertPosition.After) i++;            
  121.             if (parent == null) {
  122.                 view.Nodes.Insert(i, n);
  123.             } 
  124.             else {
  125.                 parent.Nodes.Insert(i, n);
  126.                 if (selectIt && !parent.IsExpanded) {
  127.                     parent.Expand(); // this will change image index of leaf nodes.
  128.                 }
  129.             }
  130.             n.Invalidate();
  131.             if (selectIt) {
  132.                 view.SelectedNode = n;
  133.             }
  134.         }
  135.         public void Insert(int i, InsertPosition position, XmlNode n) {
  136.             if (n == null) return;
  137.             if (n.NodeType == XmlNodeType.Attribute) {
  138.                 Debug.Assert(this.xparent is XmlElement);
  139.                 XmlElement pe = (XmlElement)this.xparent;
  140.                 if (pe.Attributes != null){
  141.                     XmlNode already = pe.Attributes.GetNamedItem(n.LocalName, n.NamespaceURI);
  142.                     if (already != null){
  143.                         throw new ApplicationException(SR.DuplicateAttribute);
  144.                     }
  145.                 }
  146.                 if (pe.Attributes != null && i < pe.Attributes.Count) {
  147.                     XmlAttribute refNode = this.xparent.Attributes[i];
  148.                     if (position == InsertPosition.After){
  149.                         pe.Attributes.InsertAfter((XmlAttribute)n, refNode);
  150.                     } else {
  151.                         pe.Attributes.InsertBefore((XmlAttribute)n, refNode);
  152.                     }
  153.                 } else {
  154.                     pe.Attributes.Append((XmlAttribute)n);
  155.                 }
  156.             } else {
  157.                 i -= this.AttributeCount;
  158.                 if (this.xparent.HasChildNodes && i < this.xparent.ChildNodes.Count) {
  159.                     XmlNode refNode = this.xparent.ChildNodes[i];
  160.                     if (position == InsertPosition.After) {
  161.                         this.xparent.InsertAfter(n, refNode);
  162.                     } else {
  163.                         this.xparent.InsertBefore(n, refNode);
  164.                     }
  165.                 } else {
  166.                     this.xparent.AppendChild(n);
  167.                 }
  168.             }
  169.         }
  170.         public void Remove(XmlTreeNode n) {
  171.             if (n.Node != null) {
  172.                 Remove(n.Node);
  173.             }
  174.             n.Remove();
  175.         }
  176.         void Remove(XmlNode n) {
  177.             if (n != null && this.originalParent != null) {
  178.                 if (n.NodeType == XmlNodeType.Attribute) {
  179.                     Debug.Assert(this.originalParent is XmlElement);
  180.                     this.originalParent.Attributes.Remove((XmlAttribute)n);
  181.                 } else {
  182.                     this.originalParent.RemoveChild(n);
  183.                 }
  184.             }
  185.         }
  186.     }
  187.     public class EditNodeName : Command {
  188.         Command cmd;
  189.         public EditNodeName(XmlTreeNode node, XmlName newName, bool autoGenPrefixes) {
  190.             if (node.Node == null) {
  191.                 throw new ArgumentException(SR.NodeNotCreated);
  192.             }
  193.             switch (node.NodeType) {
  194.                 case XmlNodeType.Element:
  195.                     cmd = new EditElementName(node, newName, autoGenPrefixes);
  196.                     break;
  197.                 case XmlNodeType.Attribute:
  198.                     cmd = new EditAttributeName(node, newName, autoGenPrefixes);
  199.                     break;
  200.                 case XmlNodeType.ProcessingInstruction:
  201.                     cmd = new EditProcessingInstructionName(node, newName.LocalName);
  202.                     break;
  203.                 default:
  204.                     throw new ArgumentException(
  205.                         string.Format(SR.NodeNameNotEditable, node.NodeType.ToString()));
  206.             }
  207.         }
  208.         public EditNodeName(XmlTreeNode node, string newName) {
  209.             if (node.Node == null) {
  210.                 throw new ArgumentException(SR.NodeNotCreated);
  211.             }
  212.             switch (node.NodeType) {
  213.                 case XmlNodeType.Element:
  214.                     cmd = new EditElementName(node, newName);
  215.                     break;
  216.                 case XmlNodeType.Attribute:
  217.                     cmd = new EditAttributeName(node, newName);
  218.                     break;
  219.                 case XmlNodeType.ProcessingInstruction:
  220.                     cmd = new EditProcessingInstructionName(node, newName);
  221.                     break;                    
  222.                 default:
  223.                     throw new ArgumentException(
  224.                         string.Format(SR.NodeNameNotEditable, node.NodeType.ToString()));
  225.             }
  226.         }
  227.         public override string Name { get { return cmd.Name; } }
  228.         public override void Do() {
  229.             cmd.Do();
  230.         }
  231.         public override void Undo() {
  232.             cmd.Undo();
  233.         }
  234.         public override void Redo() {
  235.             cmd.Redo();
  236.         }
  237.         public override bool IsNoop {
  238.             get { return false; }
  239.         }
  240.     }
  241.     /// <summary>
  242.     /// Change the name of an attribute.
  243.     /// </summary>
  244.     public class EditAttributeName : Command {
  245.         XmlAttribute a;
  246.         XmlAttribute na;
  247.         XmlElement p;
  248.         XmlTreeNode node;
  249.         XmlName name;
  250.         InsertNode xmlns; // generated prefix
  251.         bool autoGenPrefixes = true;
  252.         public EditAttributeName(XmlAttribute attr, NodeLabelEditEventArgs e) {
  253.             this.a = attr;
  254.             this.node = e.Node as XmlTreeNode;
  255.             this.p = this.a.OwnerElement;
  256.             Debug.Assert(this.p != null);
  257.             name = XmlHelpers.ParseName(this.p, e.Label, XmlNodeType.Attribute);
  258.         }
  259.         public EditAttributeName(XmlTreeNode node, string newName) {
  260.             this.a = (XmlAttribute)node.Node;
  261.             this.node = node;
  262.             this.p = this.a.OwnerElement;
  263.             Debug.Assert(this.p != null);
  264.             name = XmlHelpers.ParseName(this.p, newName, XmlNodeType.Attribute);
  265.         }
  266.         public EditAttributeName(XmlTreeNode node, XmlName newName, bool autoGenPrefixes) {
  267.             this.a = (XmlAttribute)node.Node;
  268.             this.node = node;
  269.             name = newName;
  270.             this.autoGenPrefixes = autoGenPrefixes;
  271.         }
  272.         public override string Name { get { return SR.EditNameCommand; } }
  273.         public override bool IsNoop {
  274.             get {
  275.                 return this.a.LocalName == name.LocalName && this.a.Prefix == name.Prefix &&
  276.                     this.a.NamespaceURI == name.NamespaceUri;
  277.             }
  278.         }
  279.         public override void Do() {
  280.             XmlAttribute nsa = null;
  281.             this.p = this.a.OwnerElement; // just in case a prior command changed this!
  282.             if (autoGenPrefixes && XmlHelpers.MissingNamespace(name)) {
  283.                 nsa  = XmlHelpers.GenerateNamespaceDeclaration(this.p, name);                         
  284.             }
  285.             this.na = a.OwnerDocument.CreateAttribute(name.Prefix, name.LocalName, name.NamespaceUri);
  286.             this.na.Value = this.a.Value; // todo: copy children properly.
  287.             Redo();
  288.             if (nsa != null) {
  289.                 xmlns = new InsertNode(node, InsertPosition.After, nsa, false, false);
  290.                 xmlns.Do();
  291.             }
  292.         }
  293.         public override void Undo() {
  294.             if (this.xmlns != null) xmlns.Undo();
  295.             this.p.Attributes.InsertBefore(this.a, this.na);
  296.             this.p.RemoveAttributeNode(this.na);
  297.             this.node.Label = this.a.Name;
  298.             this.node.Node = this.a;
  299.             this.node.TreeView.SelectedNode = this.node;
  300.         }
  301.         public override void Redo() {
  302.             this.p.Attributes.InsertBefore(this.na, this.a);
  303.             this.p.RemoveAttributeNode(this.a);
  304.             this.node.Node = this.na;
  305.             if (this.node.Label != this.na.Name) {
  306.                 this.node.Label = this.na.Name;
  307.             }
  308.             if (this.xmlns != null) xmlns.Redo();
  309.             this.node.TreeView.SelectedNode = this.node;
  310.         }
  311.         
  312.     }
  313.     /// <summary>
  314.     /// Change the name of a processing instruction.
  315.     /// </summary>
  316.     public class EditProcessingInstructionName : Command {
  317.         XmlProcessingInstruction pi;
  318.         XmlProcessingInstruction newpi;
  319.         XmlNode p;
  320.         XmlTreeNode node;
  321.         string name;
  322.         public EditProcessingInstructionName(XmlProcessingInstruction pi, NodeLabelEditEventArgs e) {
  323.             this.pi = pi;
  324.             this.p = this.pi.ParentNode;
  325.             this.node = e.Node as XmlTreeNode;
  326.             Debug.Assert(this.p != null);
  327.             name = e.Label;
  328.             this.newpi = pi.OwnerDocument.CreateProcessingInstruction(name, pi.Data);
  329.         }
  330.         public EditProcessingInstructionName(XmlTreeNode node, string newName) {
  331.             this.pi = (XmlProcessingInstruction)node.Node;
  332.             this.p = this.pi.ParentNode;
  333.             this.node = node;
  334.             Debug.Assert(this.p != null);
  335.             name = newName;
  336.             this.newpi = pi.OwnerDocument.CreateProcessingInstruction(name, pi.Data);
  337.         }
  338.         public override string Name { get { return SR.EditNameCommand; } }
  339.         
  340.         public override void Do() {
  341.             Swap(this.pi, this.newpi);
  342.         }
  343.         public override void Undo() {
  344.             Swap(this.newpi, this.pi);
  345.         }
  346.         public override void Redo() {
  347.             Swap(this.pi, this.newpi);
  348.         }
  349.         public override bool IsNoop {
  350.             get {
  351.                 return this.pi.Target == name;
  352.             }
  353.         }
  354.         public void Swap(XmlProcessingInstruction op, XmlProcessingInstruction np) {
  355.             this.p.InsertBefore(np, op );
  356.             this.p.RemoveChild(op);
  357.             this.node.Node = np;
  358.             this.node.Label = np.Target;
  359.             this.node.TreeView.SelectedNode = this.node;
  360.         }
  361.     }
  362.     /// <summary>
  363.     /// </summary>
  364.     public class InsertNode : Command {
  365.         XmlTreeView view;
  366.         XmlDocument doc;
  367.         //XmlTreeNode n;
  368.         XmlTreeNode newNode;
  369.         TreeParent parent;
  370.         XmlNode theNode;
  371.         int pos;
  372.         XmlNodeType type;
  373.         bool requiresName;
  374.         InsertPosition position;
  375.         bool selectNewNode = true;
  376.         bool expandNewNode = true;
  377.         /// <summary>
  378.         /// Insert a new element as a sibling or child of current node. This command can create
  379.         /// new XmlTreeNodes and new XmlNodes to go with it, or it can 
  380.         /// </summary>
  381.         public InsertNode(XmlTreeView view) {
  382.             this.view = view;
  383.             this.newNode = view.CreateTreeNode();
  384.             this.doc = view.Model.Document;
  385.             this.position = InsertPosition.Child;
  386.         }
  387.         /// <summary>
  388.         /// Insert an existing XmlNode into the tree and create a corresponding XmlTreeNode for it.
  389.         /// </summary>
  390.         /// <param name="target">Anchor point for insertion</param>
  391.         /// <param name="position">Where to insert the new node relative to target node</param>
  392.         /// <param name="xnode">Provided XmlNode that the new XmlTreeNode will wrap</param>
  393.         /// <param name="selectNewNode">Whether to select the node in the tree after it's inserted.</param>
  394.         public InsertNode(XmlTreeNode target, InsertPosition position, XmlNode xnode, bool selectNewNode, bool expandNewNode) {
  395.             this.view = target.XmlTreeView;
  396.             this.doc = this.view.Model.Document;
  397.             this.position = position;
  398.             this.type = xnode.NodeType;
  399.             this.newNode = new XmlTreeNode(this.view, xnode);
  400.             Initialize(newNode, target, position);
  401.             this.selectNewNode = selectNewNode;
  402.             this.expandNewNode = expandNewNode;
  403.         }
  404.         public override string Name { get { return SR.InsertNodeCommand; } }
  405.        
  406.         // Returns false if the given insertion is illegal
  407.         public bool Initialize(XmlTreeNode n, InsertPosition position, XmlNodeType type) {
  408.             this.position = position;
  409.             this.type = type;
  410.             XmlNode xn = null;
  411.             this.newNode.NodeType = type;
  412.             if (n != null) {
  413.                 this.parent = new TreeParent(view, doc, n);
  414.                 xn = n.Node;
  415.             } else {
  416.                 position = InsertPosition.Child; ;
  417.                 xn = view.Model.Document;
  418.                 this.parent = new TreeParent(view.TreeView, view.Model.Document);
  419.             }
  420.             bool result = CanInsertNode(position, type, xn);
  421.             if (result) {
  422.                 if (position == InsertPosition.Child) {
  423.                     if (xn != null) parent.SetParent(n);
  424.                     pos = parent.AttributeCount;
  425.                     if (type != XmlNodeType.Attribute)
  426.                         pos += parent.ChildCount;
  427.                 } else {
  428.                     if (type == XmlNodeType.Attribute ^ xn is XmlAttribute) {
  429.                         pos = this.parent.AttributeCount;
  430.                         this.position = InsertPosition.Before;
  431.                     } else if (n != null) {
  432.                         pos = n.Index;
  433.                     }
  434.                 }
  435.             }
  436.             return result;
  437.         }
  438.         static bool[][] insertMap = new bool[][] {
  439.         // child -> parent                          None,  Element, Attribute, Text,  CDATA, EntityRef, Entity, PI,    Comment, Doc,   DOCTYPE, Frag,  Notation, WhiteSpace, SigWS, EndElement, EndEntity, XmlDecl                                                
  440.         /* None                     */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  441.         /* Element,                 */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  442.         /* Attribute,               */ new bool[] { false, true,    false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  443.         /* Text,                    */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   false, false,   true,  false,    false,      false, false,      false,     false },
  444.         /* CDATA,                   */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   false, false,   true,  false,    false,      false, false,      false,     false },
  445.         /* EntityReference,         */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   false, false,   true,  false,    false,      false, false,      false,     false },
  446.         /* Entity,                  */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  447.         /* ProcessingInstruction,   */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  448.         /* Comment,                 */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  449.         /* Document,                */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  450.         /* DocumentType,            */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  451.         /* DocumentFragment,        */ new bool[] { false, true,    false,     false, false, false,     false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  452.         /* Notation,                */ new bool[] { false, false,   false,     false, false, true,      false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  453.         /* Whitespace,              */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  454.         /* SignificantWhitespace,   */ new bool[] { false, true,    false,     false, false, true,      false,  false, false,   true,  false,   true,  false,    false,      false, false,      false,     false },
  455.         /* EndElement,              */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  456.         /* EndEntity,               */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   false, false,   false, false,    false,      false, false,      false,     false },
  457.         /* XmlDeclaration           */ new bool[] { false, false,   false,     false, false, false,     false,  false, false,   true,  false,   false, false,    false,      false, false,      false,     false }
  458.         };
  459.         private bool CanInsertNode(InsertPosition position, XmlNodeType type, XmlNode xn) {
  460.             if (position == InsertPosition.Before && xn.NodeType == XmlNodeType.XmlDeclaration) {
  461.                 return false; // cannot insert anything before xml declaration.
  462.             }
  463.             if (position != InsertPosition.Child) {
  464.                 xn = parent.ParentNode;
  465.             }
  466.             XmlNodeType parentType = (xn != null) ? xn.NodeType : XmlNodeType.None;
  467.             bool result = insertMap[(int)type][(int)parentType];
  468.             
  469.             // Check a few extra things...
  470.             switch (type) {
  471.                 case XmlNodeType.Attribute:
  472.                     this.requiresName = true;                    
  473.                     break;
  474.                 case XmlNodeType.Element:
  475.                     this.requiresName = true;
  476.                     if (position != InsertPosition.Child && parent.IsRoot && parent.Document != null && parent.Document.DocumentElement != null) {
  477.                         result = false; // don't allow multiple root elements.
  478.                     }
  479.                     break;
  480.                 case XmlNodeType.ProcessingInstruction:
  481.                     this.requiresName = true;                    
  482.                     break;
  483.             }
  484.             return result;
  485.         }
  486.         public void Initialize(XmlTreeNode newNode, XmlTreeNode target, InsertPosition position) {
  487.             this.newNode = newNode;
  488.             this.position = position;
  489.             if (target == null) {
  490.                 this.parent = new TreeParent(this.view.TreeView, this.doc);
  491.             } else {
  492.                 this.parent = new TreeParent(this.view, this.doc, target);
  493.                 if (position == InsertPosition.Child) {
  494.                     if (CanHaveChildren(target)) {
  495.                         this.parent.SetParent(target);
  496.                     } else {
  497.                         // if it's not an element it cannot have children!
  498.                         this.position = InsertPosition.After;
  499.                     }
  500.                 }
  501.             }
  502.             if (position == InsertPosition.Child) {
  503.                 if (target == null) {
  504.                     // inserting at rool level
  505.                     this.pos = this.view.TreeView.Nodes.Count;
  506.                 } else {
  507.                     if (!CanHaveChildren(target)) {
  508.                         this.position = InsertPosition.After;
  509.                     }
  510.                     if (newNode.NodeImage == NodeImage.Attribute) {
  511.                         this.pos = this.parent.AttributeCount;
  512.                     } else if (target != null) {
  513.                         this.pos = target.Nodes.Count;
  514.                     }
  515.                 }
  516.             }
  517.             if (this.position != InsertPosition.Child) {
  518.                 if (target.Node is XmlAttribute ^ newNode.Node is XmlAttribute) {
  519.                     pos = this.parent.AttributeCount;
  520.                     this.position = InsertPosition.Before; 
  521.                 } else if (target != null) {
  522.                     this.pos = target.Index;
  523.                 }
  524.             }
  525.         }
  526.         bool CanHaveChildren(XmlTreeNode target) {
  527.             return target.NodeType == XmlNodeType.Element ||
  528.                     target.NodeType == XmlNodeType.Document;
  529.         }
  530.         public bool RequiresName {
  531.             get { return this.requiresName; }
  532.         }
  533.         public XmlTreeNode NewNode {
  534.             get { return this.newNode; }
  535.         }
  536.         public XmlNode CreateNode(XmlNode context, string name) {
  537.             XmlNode n = null;            
  538.             switch (type) {
  539.                 case XmlNodeType.Attribute: {
  540.                         XmlName qname = XmlHelpers.ParseName(context, name, type);
  541.                         if (qname.Prefix == null) {
  542.                             n = doc.CreateAttribute(qname.LocalName);
  543.                         } else {
  544.                             n = doc.CreateAttribute(qname.Prefix, qname.LocalName, qname.NamespaceUri);
  545.                         }
  546.                     }
  547.                     break;
  548.                 case XmlNodeType.CDATA:
  549.                     n = doc.CreateCDataSection("");
  550.                     break;
  551.                 case XmlNodeType.Comment:
  552.                     n = doc.CreateComment("");
  553.                     break;
  554.                 case XmlNodeType.DocumentType:
  555.                     XmlConvert.VerifyName(name);
  556.                     n = doc.CreateDocumentType(name, null, null, null);
  557.                     break;
  558.                 case XmlNodeType.Element: {
  559.                         XmlName qname = XmlHelpers.ParseName(context, name, type);
  560.                         n = doc.CreateElement(qname.Prefix, qname.LocalName, qname.NamespaceUri);
  561.                         break;
  562.                     }
  563.                 case XmlNodeType.ProcessingInstruction:
  564.                     XmlConvert.VerifyName(name);
  565.                     if (name == "xml") {
  566.                         n = doc.CreateXmlDeclaration("1.0", null, null);
  567.                     } else {
  568.                         n = doc.CreateProcessingInstruction(name, "");
  569.                     }
  570.                     break;
  571.                 case XmlNodeType.Text:
  572.                     n = doc.CreateTextNode("");
  573.                     break;
  574.                 default:
  575.                     throw new ApplicationException(string.Format(SR.UnexpectedNodeType, type.ToString()));
  576.             }
  577.             return n;
  578.         }
  579.         public XmlNode CreateDocumentElement(string namespaceUri, string name) {
  580.             XmlNode n = null;
  581.             n = doc.CreateElement(name, namespaceUri);
  582.             return n;
  583.         }
  584.         public XmlNode XmlNode {
  585.             get { return newNode.Node; }
  586.             set {
  587.                 parent.Insert(this.pos, this.position, value);
  588.                 newNode.Node = this.theNode = value;
  589.                 view.TreeView.OnSelectionChanged();
  590.             }
  591.         }
  592.         public override bool IsNoop {
  593.             get {
  594.                 return false;
  595.             }
  596.         }
  597.         public override void Do() {
  598.             Debug.Assert(parent != null);
  599.             parent.Insert(this.pos, this.position, newNode, this.selectNewNode);
  600.             if (this.RequiresName) {
  601.                 Debug.Assert(newNode != null);
  602.                 if (this.theNode != null && newNode.Node == null) {
  603.                     this.XmlNode = this.theNode;
  604.                 }
  605.                 Debug.Assert(view != null);
  606.                 if (selectNewNode) {
  607.                     this.view.SelectedNode = newNode;
  608.                     newNode.XmlTreeView.ScrollIntoView(newNode);
  609.                 }
  610.             } else if (newNode.Node == null) {
  611.                 this.XmlNode = CreateNode(null, null);
  612.                 this.view.OnNodeInserted(newNode);
  613.             }
  614.             if (expandNewNode) {
  615.                 newNode.Expand();
  616.             }
  617.         }
  618.         public override void Undo() {
  619.             if (newNode.IsEditing) {
  620.                 newNode.EndEdit(true);
  621.             }
  622.             TreeParent np = new TreeParent(this.view, this.doc, newNode);
  623.             np.Remove(newNode);
  624.         }
  625.         public override void Redo() {
  626.             Do();
  627.         }
  628.     }
  629.     public class ChangeNode : Command {
  630.         XmlDocument doc;
  631.         XmlNodeType oldnt = XmlNodeType.Text;
  632.         XmlNodeType nt;
  633.         XmlTreeView view;
  634.         XmlTreeNode node;
  635.         XmlNode newNode;
  636.         CompoundCommand group;
  637.         XmlTreeNode newTreeNode;
  638.         public ChangeNode(XmlTreeView view, XmlTreeNode node, XmlNodeType nt) {
  639.             this.doc = view.Model.Document;
  640.             this.nt = nt;
  641.             this.view = view;
  642.             this.node = node;
  643.             XmlNode n = node.Node;
  644.             if (n == null) return;
  645.         init:
  646.             this.oldnt = n.NodeType;
  647.             string innerXml = (oldnt == XmlNodeType.Element) ? n.InnerXml : SpecialUnescape(oldnt, n.Value);
  648.             string outerXml = n.OuterXml;
  649.             string qname = n.Name;
  650.             string localName = n.LocalName;
  651.             string ns = n.NamespaceURI;
  652.             bool noName = false;                        
  653.             if (qname.StartsWith("#")) {
  654.                 qname = localName = "";
  655.             }
  656.             noName = string.IsNullOrEmpty(qname);
  657.             
  658.             if (noName && IsNamedNodeType(nt)) {
  659.                 // Try parsing the content of the node as markup! (but first check for special unescaping
  660.                 // that we do for nested comment/cdata blocks)                
  661.                 PasteCommand paste = new PasteCommand(doc, view, InsertPosition.Before, new TreeData(innerXml));
  662.                 XmlTreeNode nte = paste.NewNode;
  663.                 if (nte != null && IsNamedNodeType(nte.NodeType)) {
  664.                     // then it worked - we extracted a node with a name, so start over.
  665.                     n = newNode = nte.Node;
  666.                     goto init;
  667.                 }
  668.             }
  669.             if (newNode == null || newNode.NodeType != nt) {
  670.                 switch (nt) {
  671.                     case XmlNodeType.Element:
  672.                         if (noName) {
  673.                             qname = "element";
  674.                         }
  675.                         newNode = doc.CreateElement(qname, ns);
  676.                         newNode.InnerXml = innerXml;
  677.                         break;
  678.                     case XmlNodeType.Attribute:
  679.                         if (noName) {
  680.                             qname = "attribute";
  681.                         }
  682.                         newNode = doc.CreateAttribute(qname, ns);
  683.                         newNode.Value = innerXml;
  684.                         break;
  685.                     case XmlNodeType.Comment:
  686.                         newNode = doc.CreateComment(SpecialEscape(nt, noName ? innerXml : outerXml));
  687.                         break;
  688.                     case XmlNodeType.ProcessingInstruction:
  689.                         if (noName) {
  690.                             localName = "pi";
  691.                         }
  692.                         newNode = doc.CreateProcessingInstruction(localName, innerXml);
  693.                         break;
  694.                     case XmlNodeType.Text:
  695.                         newNode = doc.CreateTextNode(noName ? innerXml : outerXml);
  696.                         break;
  697.                     case XmlNodeType.CDATA:
  698.                         newNode = doc.CreateCDataSection(SpecialEscape(nt, noName ? innerXml : outerXml));
  699.                         break;
  700.                 }
  701.             }           
  702.             InsertNode icmd = new InsertNode(node, InsertPosition.Before, newNode, true, true);
  703.             newTreeNode = icmd.NewNode;
  704.             DeleteNode del = new DeleteNode(doc, node);
  705.             group = new CompoundCommand(this.Name);
  706.             group.Add(icmd);
  707.             group.Add(del);            
  708.         }
  709.         static string SpecialEscape(XmlNodeType nt, string value) {
  710.             if (nt == XmlNodeType.Comment) {
  711.                 // Comments cannot contain nested "--", so we do special escaping here.
  712.                 return EscapeSequence(value, "<!--", "/*", "-->", "*/");
  713.             } else if (nt == XmlNodeType.CDATA) {
  714.                 // CDATA blocks cannot nest inside CDATA blocks, so we do special escaping for that also,
  715.                 return EscapeSequence(value, "<![CDATA[", "/[", "]]>", "]/");                
  716.             }
  717.             return value;
  718.         }
  719.         static string SpecialUnescape(XmlNodeType nt, string value) {            
  720.             if (nt == XmlNodeType.Comment) {
  721.                 return UnescapeSequence(value, "<!--", "/*", "-->", "*/");
  722.             } else if (nt == XmlNodeType.CDATA) {
  723.                 return UnescapeSequence(value, "<![CDATA[", "/[", "]]>", "]/");
  724.             }
  725.             return value;
  726.         }
  727.         static string EscapeSequence(string value, string start, string open, string end, string close) {
  728.             value = value.Replace(start, open);
  729.             value = value.Replace(end, close);
  730.             return value;
  731.         }
  732.         static string UnescapeSequence(string value, string start, string open, string end, string close) {
  733.             Debug.Assert(open.Length == 2 && close.Length == 2);
  734.             char a = open[0];
  735.             char b = open[1];
  736.             char x = close[0];
  737.             char y = close[1];
  738.             StringBuilder sb = new StringBuilder();
  739.             int depth = 0;
  740.             for (int i = 0, n = value.Length; i < n; i++) {
  741.                 char c = value[i];
  742.                 if (c == a && i + 1 < n && value[i + 1] == b) {
  743.                     if (depth == 0) {
  744.                         sb.Append(start);
  745.                     } else {
  746.                         sb.Append(a);
  747.                         sb.Append(b);
  748.                     }
  749.                     depth++;
  750.                     i++;
  751.                 } else if (c == x && i + 1 < n && value[i + 1] == y) {
  752.                     depth--;
  753.                     if (depth == 0) {
  754.                         sb.Append(end);
  755.                     } else {
  756.                         sb.Append(x);
  757.                         sb.Append(y);
  758.                     }
  759.                     i++;
  760.                 } else {
  761.                     sb.Append(c);
  762.                 }
  763.             }
  764.             return sb.ToString();
  765.         }
  766.         bool IsNamedNodeType(XmlNodeType nt) {
  767.             switch (nt) {
  768.                 case XmlNodeType.Attribute:
  769.                 case XmlNodeType.Element:
  770.                 case XmlNodeType.ProcessingInstruction:
  771.                     return true;
  772.             }
  773.             return false;
  774.         }
  775.         public XmlTreeNode NewNode {
  776.             get {
  777.                 return newTreeNode;
  778.             }
  779.         }
  780.         public override bool IsNoop {
  781.             get { return false; }
  782.         }
  783.         public override string Name {
  784.             get { return string.Format(SR.ChangeNodeCommand, nt.ToString()); }
  785.         }
  786.         public override void Do() {            
  787.             group.Do();
  788.         }
  789.         public override void Redo() {
  790.             group.Redo();
  791.             
  792.         }
  793.         public override void Undo() {
  794.             group.Undo();
  795.         }
  796.     }
  797.     public class EditElementName : Command {
  798.         XmlElement xe;
  799.         XmlElement ne;
  800.         XmlNode p;
  801.         XmlTreeNode node;
  802.         XmlName name;
  803.         InsertNode xmlns; // generated prefix
  804.         bool autoGenPrefixes = true;
  805.         public EditElementName(XmlElement n, NodeLabelEditEventArgs e) {
  806.             this.xe = n;
  807.             this.node = e.Node as XmlTreeNode;
  808.             this.name = XmlHelpers.ParseName(n, e.Label, n.NodeType);
  809.         }
  810.         public EditElementName(XmlTreeNode node, string newName) {
  811.             this.xe = (XmlElement)node.Node; ;
  812.             this.node = node;
  813.             this.name = XmlHelpers.ParseName(this.xe, newName, node.NodeType);
  814.         }
  815.         public EditElementName(XmlTreeNode node, XmlName newName, bool autoGenPrefixes) {
  816.             this.xe = (XmlElement)node.Node; ;
  817.             this.node = node;
  818.             this.name = newName;
  819.             this.autoGenPrefixes = autoGenPrefixes;
  820.         }
  821.         public override string Name { get { return SR.EditNameCommand; } }
  822.         public override bool IsNoop {
  823.             get {
  824.                 return this.xe.LocalName == name.LocalName && this.xe.Prefix == name.Prefix &&
  825.                     this.xe.NamespaceURI == name.NamespaceUri;
  826.             }
  827.         }
  828.         public override void Do() {
  829.             this.p = xe.ParentNode; // in case a prior command changed this!
  830.             XmlAttribute a = null;
  831.             if (autoGenPrefixes && XmlHelpers.MissingNamespace(name)) {
  832.                 a = XmlHelpers.GenerateNamespaceDeclaration(xe, name);                
  833.             }
  834.             this.ne = xe.OwnerDocument.CreateElement(name.Prefix, name.LocalName, name.NamespaceUri); 
  835.             Redo();
  836.             if (a != null) {
  837.                 xmlns = new InsertNode(node, InsertPosition.Child, a, false, false);
  838.                 xmlns.Do();
  839.             }            
  840.         }
  841.         public override void Undo() {
  842.             if (this.xmlns != null) xmlns.Undo();
  843.             Move(ne, xe);            
  844.             this.p.ReplaceChild(xe, ne);
  845.             node.Node = xe;
  846.             node.TreeView.SelectedNode = node;
  847.         }
  848.         public override void Redo() {
  849.             // Since you cannot rename an element using the DOM, create new element 
  850.             // and copy all children over.
  851.             Move(xe, ne);
  852.             this.p.ReplaceChild(ne, xe);
  853.             node.Node = ne;
  854.             if (this.xmlns != null) xmlns.Redo();
  855.             node.TreeView.SelectedNode = node;
  856.         }
  857.         static void Move(XmlElement from, XmlElement to) {
  858.             ArrayList move = new ArrayList();
  859.             foreach (XmlAttribute a in from.Attributes) {
  860.                 if (a.Specified) {
  861.                     move.Add(a);
  862.                 }
  863.             }
  864.             foreach (XmlAttribute a in move) {
  865.                 from.Attributes.Remove(a);
  866.                 to.Attributes.Append(a);
  867.             }
  868.             while (from.HasChildNodes) {
  869.                 to.AppendChild(from.FirstChild);
  870.             }
  871.         }
  872.     }
  873.     /// <summary>
  874.     /// Change the value of a node.
  875.     /// </summary>
  876.     public class EditNodeValue : Command {
  877.         XmlTreeNode n;
  878.         XmlNode xn;
  879.         string newValue;
  880.         string oldValue;
  881.         XmlTreeView view;
  882.         public EditNodeValue(XmlTreeView view, XmlTreeNode n, string newValue) {
  883.             this.view = view;
  884.             this.n = n;
  885.             this.xn = n.Node;
  886.             this.newValue = newValue;
  887.             if (xn is XmlElement) {
  888.                 this.oldValue = xn.InnerText;                
  889.             } else if (xn is XmlProcessingInstruction) {
  890.                 XmlProcessingInstruction pi = ((XmlProcessingInstruction)xn);
  891.                 this.oldValue = pi.Data;
  892.             } else if (xn != null) {
  893.                 this.oldValue = xn.Value;
  894.             }
  895.         }
  896.         public override string Name { get { return SR.EditValueCommand; } }
  897.         public override bool IsNoop {
  898.             get {
  899.                 return this.oldValue == this.newValue; 
  900.             }
  901.         }
  902.         void SetValue(string value) {
  903.             if (xn is XmlElement) {
  904.                 xn.InnerText = value;
  905.                 n.RemoveChildren();
  906.                 if (!string.IsNullOrEmpty(value)){
  907.                    // Add text node child.
  908.                     XmlTreeNode text = view.CreateTreeNode();
  909.                     text.Node = xn.FirstChild;
  910.                     n.Nodes.Add(text);                    
  911.                 }
  912.             } else if (xn is XmlProcessingInstruction) {
  913.                 XmlProcessingInstruction pi = ((XmlProcessingInstruction)xn);
  914.                 pi.Data = value;
  915.             } else if (xn != null) {
  916.                 xn.Value = value;
  917.             }
  918.             if (view != null) {
  919.                 view.SelectedNode = n;
  920.                 view.ScrollIntoView(n);
  921.             }
  922.         }
  923.         public override void Do() {
  924.             SetValue(newValue);
  925.         }
  926.         public override void Undo() {
  927.             SetValue(oldValue);
  928.         }
  929.         public override void Redo() {
  930.             SetValue(newValue);
  931.         }
  932.     }
  933.     public class DeleteNode : Command {
  934.         XmlDocument doc;
  935.         XmlTreeNode e;
  936.         TreeParent parent;
  937.         int pos;
  938.         public DeleteNode(XmlDocument doc, XmlTreeNode e) {
  939.             this.e = e;
  940.             this.doc = doc;
  941.         }
  942.         public override bool IsNoop {
  943.             get { return false; }
  944.         }
  945.         public override string Name { get { return SR.DeleteCommand; } }
  946.         public override void Do() {
  947.             if (this.parent == null) {
  948.                 this.pos = e.Index;
  949.                 this.parent = new TreeParent(e.TreeView, doc, e);
  950.             }
  951.             parent.Remove(e);
  952.         }
  953.         public override void Undo() {
  954.             parent.Insert(this.pos, InsertPosition.Before, this.e, true);
  955.         }
  956.         public override void Redo() {
  957.             Do();
  958.         }
  959.     }
  960.     public class MoveNode : Command {
  961.         XmlTreeNode source;
  962.         XmlTreeNode target;
  963.         TreeParent tp;
  964.         InsertPosition where;
  965.         TreeParent sourceParent;
  966.         int sourcePosition;
  967.         bool copy;
  968.         bool bound;
  969.         bool wasExpanded;
  970.         XmlTreeView view;
  971.         /// <summary>
  972.         /// Move or copy a node from one place to another place in the tree.
  973.         /// </summary>
  974.         /// <param name="view">The MyTreeView that we are inserting into</param>
  975.         /// <param name="source">The node that we are moving.  This node may not be in the tree
  976.         /// and that is ok, so it might be a node that is being cut&paste from another process
  977.         /// for example</param>
  978.         /// <param name="target">The existing node that establishes where in the tree we want
  979.         /// to move the source node to</param>
  980.         /// <param name="where">The position relative to the target node (before or after)</param>
  981.         /// <param name="copy">Whether we are moving or copying the source node</param>
  982.         public MoveNode(XmlTreeView view, XmlTreeNode source, XmlTreeNode target, InsertPosition where, bool copy) {
  983.             XmlNode sn = source.Node;
  984.             XmlNode dn = target.Node;
  985.             this.copy = copy;
  986.             TreeView tv = view.TreeView;
  987.             XmlDocument doc = view.Model.Document;
  988.             this.view = view;
  989.             this.sourcePosition = source.Index;
  990.             view.Model.BeginUpdate();
  991.             try {
  992.                 if (copy) {
  993.                     this.wasExpanded = source.IsExpanded;
  994.                     XmlTreeNode newSource = view.CreateTreeNode();
  995.                     if (sn != null) {
  996.                         sn = sn.CloneNode(true);
  997.                         newSource.Node = sn;
  998.                     }
  999.                     source = newSource;
  1000.                 }
  1001.                 this.sourceParent = new TreeParent(tv, doc, source);
  1002.                 this.tp = new TreeParent(tv, doc, target);
  1003.                 // normalize destination based on source node type.
  1004.                 // for example, if source is an attribute, then it can only be
  1005.                 // inserted amongst attributes of another node.
  1006.                 if (tp.IsRoot && where != InsertPosition.Child) {
  1007.                     if (sn is XmlAttribute)
  1008.                         throw new Exception(SR.RootLevelAttributes);
  1009.                     if (sn is XmlText || sn is XmlCDataSection)
  1010.                         throw new Exception(SR.RootLevelText);
  1011.                     if (sn is XmlElement && sn.OwnerDocument.DocumentElement != null && sn.OwnerDocument.DocumentElement != sn)
  1012.                         throw new Exception(SR.RootLevelElements);
  1013.                     if (dn is XmlDeclaration && where == InsertPosition.Before)
  1014.                         throw new Exception(SR.RootLevelBeforeXmlDecl);
  1015.                 }
  1016.                 if (where != InsertPosition.Child) {
  1017.                     if (sn is XmlAttribute) {
  1018.                         if (!(dn is XmlAttribute)) {
  1019.                             if (tp.AttributeCount != 0) {
  1020.                                 // move target to valid location for attributes.
  1021.                                 target = tp.GetChild(tp.AttributeCount - 1);
  1022.                                 where = InsertPosition.After;
  1023.                             } else {
  1024.                                 // append the attribute.
  1025.                                 where = InsertPosition.Child;
  1026.                                 target = (XmlTreeNode)target.Parent;
  1027.                             }
  1028.                         }
  1029.                     } else if (dn is XmlAttribute) {
  1030.                         if (!(sn is XmlAttribute)) {
  1031.                             int skip = tp.AttributeCount;
  1032.                             if (tp.Count > skip) {
  1033.                                 // Move non-attribute down to beginning of child elements.
  1034.                                 target = tp.GetChild(skip);
  1035.                                 where = InsertPosition.Before;
  1036.                             } else {
  1037.                                 // append the node.
  1038.                                 where = InsertPosition.Child;
  1039.                                 target = (XmlTreeNode)target.Parent;
  1040.                             }
  1041.                         }
  1042.                     }
  1043.                 }
  1044.                 this.source = source;
  1045.                 this.target = target;
  1046.                 this.where = where;
  1047.                 this.tp = new TreeParent(tv, doc, target);
  1048.                 if (where == InsertPosition.Child) {
  1049.                     this.tp.SetParent(target);
  1050.                 }
  1051.             } finally {
  1052.                 view.Model.EndUpdate();
  1053.             }
  1054.         }
  1055.         public override string Name { get { return SR.MoveCommand; } }
  1056.         public XmlTreeNode Source { get { return this.source; }}
  1057.         public override bool IsNoop {
  1058.             get { return this.source == this.target; }
  1059.         }
  1060.         public override void Do() {
  1061.             XmlNode sn = source.Node;
  1062.             //XmlNode dn = target.Node;
  1063.             XmlTreeNode sp = (XmlTreeNode)source.Parent;
  1064.             
  1065.             int sindex = this.sourcePosition;
  1066.             TreeView tv = source.TreeView;
  1067.             if (tv != null){
  1068.                 this.sourceParent.Remove(source);
  1069.             }
  1070.             int index = target.Index;
  1071.             if (where == InsertPosition.Child) {
  1072.                 if (sn is XmlAttribute) {
  1073.                     index = this.tp.AttributeCount;
  1074.                 } else {
  1075.                     index = this.tp.AttributeCount + this.tp.ChildCount;
  1076.                 }
  1077.             }
  1078.             try {
  1079.                 this.tp.Insert(index, where, source, true);
  1080.             } catch (Exception){
  1081.                 if (sp != null){
  1082.                     sp.Nodes.Insert(sindex, source);
  1083.                 } else if (tv != null) {
  1084.                     tv.Nodes.Insert(sindex, source);
  1085.                 }
  1086.                 if (tv != null) {
  1087.                     source.TreeView.SelectedNode = source;
  1088.                 }
  1089.                 throw;
  1090.             }
  1091.             
  1092.             if (this.copy && !bound){
  1093.                 bound = true;
  1094.                 this.view.Invalidate(); // Bind(source.Nodes, (XmlNode)source.Tag);
  1095.             }
  1096.             if (this.wasExpanded ){
  1097.                 source.Expand();
  1098.             }
  1099.             
  1100.             source.TreeView.SelectedNode = source;
  1101.         }
  1102.         public override void Undo() {
  1103.             // Cannot use this.sourceParent because this points to the old source position
  1104.             // not the current position.
  1105.             TreeParent parent = new TreeParent(this.sourceParent.View, this.sourceParent.Document, this.source);
  1106.             parent.Remove(this.source);
  1107.             // If the node was not in the tree, then undo just removes it, it does not
  1108.             // have to re-insert back in a previous position, because it was a new node
  1109.             // (probably inserted via drag/drop).
  1110.             if (this.sourceParent.IsNodeInTree) {                
  1111.                 this.sourceParent.Insert(this.sourcePosition, InsertPosition.Before, source, true);
  1112.                 if (source.Parent != null && source.Parent.Nodes.Count == 1) {
  1113.                     source.Parent.Expand();
  1114.                 }
  1115.                 source.TreeView.SelectedNode = source;
  1116.             } else {
  1117.                 this.target.TreeView.SelectedNode = target;
  1118.             }
  1119.         }
  1120.         public override void Redo() {
  1121.             Do();
  1122.         }
  1123.     }
  1124.     public enum NudgeDirection { Up, Down, Left, Right }
  1125.     public class NudgeNode : Command {
  1126.         XmlTreeNode node;
  1127.         NudgeDirection dir;
  1128.         MoveNode mover;
  1129.         XmlTreeView view;
  1130.         public NudgeNode(XmlTreeView view, XmlTreeNode node, NudgeDirection dir) {
  1131.             this.node = node;
  1132.             this.dir = dir;
  1133.             this.view = view;
  1134.         }
  1135.         public override string Name { get { return SR.NudgeCommand; } }
  1136.         public override bool IsNoop {
  1137.             get {
  1138.                 MoveNode cmd = GetMover();
  1139.                 return (cmd == null || cmd.IsNoop);
  1140.             }
  1141.         }
  1142.         public bool IsEnabled {
  1143.             get {
  1144.                 switch (dir) {
  1145.                     case NudgeDirection.Up:
  1146.                         return CanNudgeUp;
  1147.                     case NudgeDirection.Down:
  1148.                         return CanNudgeDown;
  1149.                     case NudgeDirection.Left:
  1150.                         return CanNudgeLeft;
  1151.                     case NudgeDirection.Right:
  1152.                         return CanNudgeRight;
  1153.                 }
  1154.                 return false;
  1155.             }
  1156.         }
  1157.         public override void Do() {
  1158.             MoveNode cmd = GetMover();
  1159.             if (cmd != null)
  1160.                 cmd.Do();
  1161.         }
  1162.         public override void Undo() {
  1163.             MoveNode cmd = GetMover();
  1164.             if (cmd != null)
  1165.                 cmd.Undo();
  1166.         }
  1167.         public override void Redo() {
  1168.             Do();
  1169.         }
  1170.         MoveNode GetMover() {
  1171.             if (this.mover == null) {
  1172.                 switch (dir) {
  1173.                     case NudgeDirection.Up:
  1174.                         this.mover = GetNudgeUp();
  1175.                         break;
  1176.                     case NudgeDirection.Down:
  1177.                         this.mover = GetNudgeDown();
  1178.                         break;
  1179.                     case NudgeDirection.Left:
  1180.                         this.mover = GetNudgeLeft();
  1181.                         break;
  1182.                     case NudgeDirection.Right:
  1183.                         this.mover = GetNudgeRight();
  1184.                         break;
  1185.                 }
  1186.             }
  1187.             return this.mover;
  1188.         }
  1189.         public bool CanNudgeUp {
  1190.             get {
  1191.                 if (node != null) {
  1192.                     XmlTreeNode prev = (XmlTreeNode)node.PrevNode;
  1193.                     if (prev != null) {
  1194.                         if (prev.Node is XmlAttribute && !(node.Node is XmlAttribute)) {
  1195.                             return false;
  1196.                         } else {
  1197.                             return true;
  1198.                         }
  1199.                     }
  1200.                 }
  1201.                 return false;
  1202.             }
  1203.         }
  1204.         public MoveNode GetNudgeUp() {
  1205.             if (node != null) {
  1206.                 XmlTreeNode prev = (XmlTreeNode)node.PrevNode;
  1207.                 if (prev != null) {
  1208.                     if (prev.Node is XmlAttribute && !(node.Node is XmlAttribute)) {
  1209.                         prev = (XmlTreeNode)node.Parent;
  1210.                     }
  1211.                     return new MoveNode(this.view, node, prev, InsertPosition.Before, false);
  1212.                 }
  1213.             }
  1214.             return null;
  1215.         }
  1216.         public bool CanNudgeDown {
  1217.             get {
  1218.                 if (node != null) {
  1219.                     XmlTreeNode next = (XmlTreeNode)node.NextSiblingNode;
  1220.                     if (next != null) {
  1221.                         return true;
  1222.                     }
  1223.                 }
  1224.                 return false;
  1225.             }
  1226.         }
  1227.         public MoveNode GetNudgeDown() {
  1228.             if (node != null) {
  1229.                 XmlTreeNode next = (XmlTreeNode)node.NextSiblingNode;
  1230.                 if (next != null) {
  1231.                     if (node.Parent != next.Parent) {
  1232.                         return new MoveNode(this.view, node, next, InsertPosition.Before, false);
  1233.                     } else {
  1234.                         return new MoveNode(this.view, node, next, InsertPosition.After, false);
  1235.                     }
  1236.                 }
  1237.             }
  1238.             return null;
  1239.         }
  1240.         public bool CanNudgeLeft {
  1241.             get {
  1242.                 if (node != null) {
  1243.                     XmlTreeNode xn = (XmlTreeNode)node;
  1244.                     XmlTreeNode parent = (XmlTreeNode)node.Parent;
  1245.                     if (parent != null) {
  1246.                         if (xn.Node is XmlAttribute) {
  1247.                             XmlAttribute a = (XmlAttribute)xn.Node;
  1248.                             if (IsDocumentElement(parent)) {
  1249.                                 // cannot move attributes outside of document element
  1250.                                 return false;
  1251.                             }
  1252.                             if (parent.Node != null && parent.Node.ParentNode != null) {
  1253.                                 XmlAttributeCollection ac = parent.Node.ParentNode.Attributes;
  1254.                                 if (ac != null && ac.GetNamedItem(a.Name, a.NamespaceURI) != null) {
  1255.                                     // parent already has this attribute!
  1256.                                     return false;
  1257.                                 }
  1258.                             }
  1259.                         }
  1260.                         return true;
  1261.                     }
  1262.                 }
  1263.                 return false;
  1264.             }
  1265.         }
  1266.         static bool IsDocumentElement(XmlTreeNode node) {
  1267.             return node.Node != null && node.Node == node.Node.OwnerDocument.DocumentElement;
  1268.         }
  1269.         public MoveNode GetNudgeLeft() {
  1270.             if (node != null) {
  1271.                 XmlTreeNode parent = (XmlTreeNode)node.Parent;
  1272.                 if (parent != null) {
  1273.                     if (node.Index == 0 && node.Index != parent.Nodes.Count-1) {
  1274.                         return new MoveNode(this.view, node, parent, InsertPosition.Before, false);
  1275.                     } else {
  1276.                         return new MoveNode(this.view, node, parent, InsertPosition.After, false);
  1277.                     }
  1278.                 }
  1279.             }
  1280.             return null;
  1281.         }
  1282.         public bool CanNudgeRight {
  1283.             get {
  1284.                 if (node != null) {
  1285.                     XmlTreeNode prev = (XmlTreeNode)node.PrevNode;
  1286.                     if (prev != null && prev != node.Parent) {
  1287.                         if (prev.Node is XmlElement) {
  1288.                             return true;
  1289.                         }
  1290.                     }
  1291.                 }
  1292.                 return false;
  1293.             }
  1294.         }
  1295.         public MoveNode GetNudgeRight() {
  1296.             if (node != null) {
  1297.                 XmlTreeNode prev = (XmlTreeNode)node.PrevNode;
  1298.                 if (prev != null && prev != node.Parent) {
  1299.                     if (prev.Node is XmlElement) {
  1300.                         return new MoveNode(this.view, node, prev, InsertPosition.Child, false);
  1301.                     }
  1302.                 }
  1303.             }
  1304.             return null;
  1305.         }
  1306.     }
  1307.     /// <summary>
  1308.     /// The TreeData class encapsulates the process of copying the XmlTreeNode to the
  1309.     /// clipboard and back. This is a custom IDataObject that supports the custom
  1310.     /// TreeData format, and string.
  1311.     /// </summary>
  1312.     [Serializable]
  1313.     public class TreeData : IDataObject {
  1314.         int img;
  1315.         string xml;
  1316.         int nodeType;
  1317.         MemoryStream stm;
  1318.         public TreeData(MemoryStream stm){
  1319.             this.stm = stm;
  1320.             this.img = -1;
  1321.         }
  1322.         public TreeData(string xml ) {
  1323.             this.xml = xml;
  1324.             this.img = -1;
  1325.         }
  1326.         public TreeData(XmlTreeNode node) {
  1327.             img = node.ImageIndex;
  1328.             XmlNode x = node.Node;
  1329.             if (x != null) {
  1330.                 nodeType = (int)x.NodeType;
  1331.                 this.xml = x.OuterXml;
  1332.             }
  1333.         }
  1334.         public static void SetData(XmlTreeNode node) {
  1335.             if (node.Node != null) {
  1336.                 Clipboard.SetDataObject(new TreeData(node));
  1337.             }
  1338.         }
  1339.         public static bool HasData {
  1340.             get {
  1341.                 try {
  1342.                     IDataObject data = Clipboard.GetDataObject();
  1343.                     if (data.GetDataPresent(typeof(string)))
  1344.                         return true;
  1345.                     foreach (string format in data.GetFormats()){
  1346.                         if (format == typeof(TreeData).FullName)
  1347.                             return true;
  1348.                         if (format.ToUpper().StartsWith("XML"))
  1349.                             return true;
  1350.                     }                    
  1351.                 } catch (System.Runtime.InteropServices.ExternalException){
  1352.                 } catch (System.Threading.ThreadStateException){
  1353.                 }
  1354.                 return false;
  1355.             }
  1356.         }
  1357.         public static TreeData GetData() {
  1358.             try {
  1359.                 IDataObject data = Clipboard.GetDataObject();
  1360.                 try {
  1361.                     if (data.GetDataPresent(typeof(TreeData))) {
  1362.                         return data.GetData(typeof(TreeData)) as TreeData;
  1363.                     }
  1364.                     foreach (string format in data.GetFormats()){
  1365.                         if (format.ToUpper().StartsWith("XML")){
  1366.                             MemoryStream raw = data.GetData(format) as MemoryStream;
  1367.                             return new TreeData(raw);
  1368.                         }
  1369.                     }   
  1370.                 } catch (Exception ){
  1371.                 }
  1372.                 if (data.GetDataPresent(typeof(string))) {
  1373.                     string xml = data.GetData(typeof(string)).ToString();
  1374.                     // We don't want to actually parse the XML at this point, 
  1375.                     // because we don't have the namespace context yet.
  1376.                     // So we just sniff the XML to determine the node type.
  1377.                     return new TreeData(xml);
  1378.                 }
  1379.             } catch (System.Runtime.InteropServices.ExternalException){
  1380.             } catch (System.Threading.ThreadStateException){
  1381.             }            
  1382.             return null;
  1383.         }
  1384.         public XmlTreeNode GetTreeNode(XmlDocument owner, XmlTreeNode target, XmlTreeView view) {
  1385.             XmlTreeNode node = view.CreateTreeNode();
  1386.             
  1387.             if (this.img == -1 && this.xml != null){
  1388.                 Regex regex = new Regex(@"[:_.w]+s*=s*(""[^""]*"")|('[^']*')s*");
  1389.                 Match m = regex.Match(xml);
  1390.                 string trimmed = xml.Trim();
  1391.                 if (m.Success && m.Index == 0 && m.Length == xml.Length) {
  1392.                     nodeType = (int)XmlNodeType.Attribute;
  1393.                     img = (int)NodeImage.Attribute - 1;
  1394.                 } else if (trimmed.StartsWith("<?")) {
  1395.                     nodeType = (int)XmlNodeType.ProcessingInstruction;
  1396.                     img = (int)NodeImage.PI - 1;
  1397.                 } else if (trimmed.StartsWith("<!--")) {
  1398.                     nodeType = (int)XmlNodeType.Comment;
  1399.                     img = (int)NodeImage.Comment - 1;
  1400.                 } else if (trimmed.StartsWith("<![CDATA[")) {
  1401.                     nodeType = (int)XmlNodeType.CDATA;
  1402.                     img = (int)NodeImage.CData - 1;
  1403.                 } else if (trimmed.StartsWith("<")) {
  1404.                     nodeType = (int)XmlNodeType.Element;
  1405.                     img = (int)NodeImage.Element - 1;
  1406.                 } else {
  1407.                     nodeType = (int)XmlNodeType.Text;
  1408.                     img = (int)NodeImage.Text - 1;
  1409.                 }
  1410.             }
  1411.             XmlNode xn = null;
  1412.             XmlNode context = (target != null) ? target.Node : owner;
  1413.             if (this.nodeType == (int)XmlNodeType.Attribute) {
  1414.                 int i = this.xml.IndexOf('=');
  1415.                 if (i > 0) {
  1416.                     string name = this.xml.Substring(0, i).Trim();
  1417.                     XmlName qname = XmlHelpers.ParseName(context, name, XmlNodeType.Attribute);
  1418.                     xn = owner.CreateAttribute(qname.Prefix, qname.LocalName, qname.NamespaceUri);
  1419.                     string s = this.xml.Substring(i + 1).Trim();
  1420.                     if (s.Length > 2) {
  1421.                         char quote = s[0];
  1422.                         s = s.Substring(1, s.Length - 2); // strip off quotes
  1423.                         // un-escape quotes in the value.
  1424.                         xn.Value = s.Replace(quote == ''' ? "&apos;" : "&quot;", quote.ToString());
  1425.                     }
  1426.                 }
  1427.             } else {
  1428.                 XmlNamespaceManager nsmgr = XmlHelpers.GetNamespaceScope(context);
  1429.                 XmlParserContext pcontext = new XmlParserContext(owner.NameTable, nsmgr, null, XmlSpace.None);
  1430.                 XmlTextReader r = null;
  1431.                 if (this.xml != null) {
  1432.                     r = new XmlTextReader(this.xml, XmlNodeType.Element, pcontext);
  1433.                 } else {
  1434.                     r = new XmlTextReader(this.stm, XmlNodeType.Element, pcontext);
  1435.                 }
  1436.                 r.WhitespaceHandling = WhitespaceHandling.Significant;
  1437.                 // TODO: add multi-select support, so we can insert multiple nodes also.
  1438.                 // And find valid nodes (for example, don't attempt to insert Xml declaration
  1439.                 // if target node is not at the top of the document, etc).
  1440.                 // For now we just favor XML elements over other node types.
  1441.                 ArrayList list = new ArrayList();
  1442.                 while (true){
  1443.                     XmlNode rn = owner.ReadNode(r);
  1444.                     if (rn == null)
  1445.                         break;
  1446.                     if (rn is XmlElement){
  1447.                         xn = rn;
  1448.                         NormalizeNamespaces((XmlElement)rn, nsmgr);
  1449.                     }
  1450.                     list.Add(rn);
  1451.                 }
  1452.                 if (xn == null && list.Count>0)
  1453.                     xn = list[0] as XmlNode;
  1454.             }
  1455.             node.Node = xn;            
  1456.             
  1457.             if (!(xn is XmlAttribute)) {                 
  1458.                 view.Invalidate();
  1459.                 if (xn is XmlElement){
  1460.                     if (node.Nodes.Count <= 1){
  1461.                         this.img = ((int)NodeImage.Leaf -1);
  1462.                     }
  1463.                 }
  1464.             }
  1465.             return node;
  1466.         }
  1467.         static void NormalizeNamespaces(XmlElement node, XmlNamespaceManager mgr) {
  1468.             if (node.HasAttributes) {
  1469.                 ArrayList toRemove = null;
  1470.                 foreach (XmlAttribute a in node.Attributes) {
  1471.                     string prefix = null;
  1472.                     string nsuri = null;
  1473.                     if (a.Prefix == "xmlns") {
  1474.                         prefix = a.LocalName;
  1475.                         nsuri = a.Value;
  1476.                     } else if (a.LocalName == "xmlns") {
  1477.                         prefix = a.Prefix;
  1478.                         nsuri = a.Value;
  1479.                     }
  1480.                     if (prefix != null && mgr.LookupNamespace(prefix) == nsuri){
  1481.                         if (toRemove == null) toRemove = new ArrayList();
  1482.                         toRemove.Add(a);
  1483.                     }
  1484.                 }
  1485.                 if (toRemove != null) {
  1486.                     foreach (XmlAttribute a in toRemove) {
  1487.                         node.Attributes.Remove(a);
  1488.                     }
  1489.                 }
  1490.             }
  1491.         }
  1492.         #region IDataObject Members
  1493.         public object GetData(Type format) {
  1494.             if (format == typeof(string)) {
  1495.                 return this.xml;
  1496.             } else if (format == typeof(TreeData)) {
  1497.                 return this;
  1498.             }
  1499.             return null;
  1500.         }
  1501.         public object GetData(string format) {
  1502.             if (format == DataFormats.Text || format == DataFormats.UnicodeText || 
  1503.                 format == DataFormats.GetFormat("XML").Name) {
  1504.                 return this.xml;
  1505.             } else if (format == DataFormats.GetFormat(typeof(TreeData).FullName).Name) {
  1506.                 return this;
  1507.             }
  1508.             return null;
  1509.         }
  1510.         public object GetData(string format, bool autoConvert) {
  1511.             return GetData(format);
  1512.         }
  1513.         public bool GetDataPresent(Type format) {
  1514.             return (format == typeof(string) ||
  1515.                 format == typeof(XmlTreeNode));
  1516.         }
  1517.         public bool GetDataPresent(string format) {
  1518.             return (format == DataFormats.Text || format == DataFormats.UnicodeText ||
  1519.                 format == DataFormats.GetFormat("XML").Name ||
  1520.                 format == DataFormats.GetFormat(typeof(TreeData).FullName).Name);
  1521.         }
  1522.         public bool GetDataPresent(string format, bool autoConvert) {
  1523.             return GetDataPresent(format);
  1524.         }
  1525.         public string[] GetFormats() {
  1526.             return new string[] {
  1527.                  DataFormats.Text,
  1528.                  DataFormats.UnicodeText,
  1529.                  DataFormats.GetFormat("XML").Name,
  1530.                  DataFormats.GetFormat(typeof(TreeData).FullName).Name
  1531.              };
  1532.         }
  1533.         public string[] GetFormats(bool autoConvert) {
  1534.             return GetFormats();
  1535.         }
  1536.         public void SetData(object data) {
  1537.             throw new NotImplementedException();
  1538.         }
  1539.         public void SetData(Type format, object data) {
  1540.             throw new NotImplementedException();
  1541.         }
  1542.         public void SetData(string format, object data) {
  1543.             throw new NotImplementedException();
  1544.         }
  1545.         public void SetData(string format, bool autoConvert, object data) {
  1546.             throw new NotImplementedException();
  1547.         }
  1548.         #endregion
  1549.     }
  1550.     public class CutCommand : Command {
  1551.         XmlTreeNode node;
  1552.         TreeParent parent;
  1553.         int index;
  1554.         public CutCommand(XmlTreeView view, XmlTreeNode node) {
  1555.             this.node = node;
  1556.             this.parent = new TreeParent(view, view.Model.Document, node);
  1557.             index = node.Index;
  1558.         }
  1559.         public override bool IsNoop {
  1560.             get {
  1561.                 return false;
  1562.             }
  1563.         }
  1564.         public override string Name { get { return SR.CutCommand; } }
  1565.         public override void Do() {
  1566.             TreeData.SetData(node);
  1567.             this.parent.Remove(node);
  1568.         }
  1569.         public override void Undo() {
  1570.             parent.Insert(this.index, InsertPosition.Before, node, true);
  1571.         }
  1572.         public override void Redo() {
  1573.             Do();
  1574.         }
  1575.     }
  1576.     public class PasteCommand : Command {
  1577.         XmlTreeNode target;
  1578.         //int index;
  1579.         XmlDocument doc;
  1580.         XmlTreeNode source;
  1581.         Command cmd;
  1582.         XmlTreeView view;
  1583.         InsertPosition position;
  1584.         TreeData td;
  1585.         public PasteCommand(XmlDocument doc, XmlTreeView view, InsertPosition position, TreeData data) {
  1586.             this.td = data;
  1587.             this.doc = doc;
  1588.             this.target = (XmlTreeNode)view.SelectedNode;
  1589.             if (this.target == null && view.TreeView.Nodes.Count > 0) {
  1590.                 this.target = (XmlTreeNode)view.TreeView.Nodes[0];
  1591.             }
  1592.             if (this.target != null && this.target.NodeType != XmlNodeType.Element &&
  1593.                 this.target.NodeType != XmlNodeType.Document) {
  1594.                 position = InsertPosition.After;
  1595.             }
  1596.             this.position = position;
  1597.             this.view = view;
  1598.             if (td != null) {
  1599.                 this.source = td.GetTreeNode(this.doc, this.target, this.view);
  1600.             }
  1601.         }
  1602.         public XmlTreeNode NewNode { get { return this.source; } }
  1603.         public override bool IsNoop {
  1604.             get {
  1605.                 return false;
  1606.             }
  1607.         }
  1608.         public override string Name { get { return SR.PasteCommand; } }
  1609.         public override void Do() {
  1610.             
  1611.             if (td != null) {
  1612.                 InsertNode icmd = new InsertNode(this.view);
  1613.                 icmd.Initialize(source, this.target, position);
  1614.                 this.cmd = icmd;
  1615.                 this.cmd.Do();
  1616.                 if (this.source.Nodes.Count > 1) {
  1617.                     this.source.Expand();
  1618.                 }
  1619.             }
  1620.         }
  1621.         public override void Undo() {
  1622.             if (this.cmd != null) {
  1623.                 this.cmd.Undo();
  1624.             }
  1625.         }
  1626.         public override void Redo() {
  1627.             if (this.cmd != null) {
  1628.                 this.cmd.Do();
  1629.             }
  1630.         }
  1631.     }
  1632.     public class XmlName {
  1633.         private string prefix;
  1634.         private string localName;
  1635.         private string namespaceUri;
  1636.         public string Prefix {
  1637.             get { return prefix; }
  1638.             set { prefix = value; }
  1639.         }
  1640.         public string LocalName {
  1641.             get { return localName; }
  1642.             set { localName = value; }
  1643.         }
  1644.         public string NamespaceUri {
  1645.             get { return namespaceUri; }
  1646.             set { namespaceUri = value; }
  1647.         }
  1648.     }
  1649.     public sealed class XmlHelpers {
  1650.         private XmlHelpers() { }
  1651.         public const string XmlnsUri = "http://www.w3.org/2000/xmlns/";
  1652.         public const string XmlUri = "http://www.w3.org/XML/1998/namespace";
  1653.         public static XmlName ParseName(XmlNode context, string name, XmlNodeType nt) {
  1654.             XmlName result = new XmlName();
  1655.             XmlConvert.VerifyName(name);
  1656.             int i = name.IndexOf(':');
  1657.             if (i>0){
  1658.                 string prefix = result.Prefix = name.Substring(0,i);
  1659.                 result.LocalName = name.Substring(i + 1);
  1660.                 if (prefix == "xml") {
  1661.                     result.NamespaceUri = XmlUri; 
  1662.                 } else if (prefix == "xmlns") {
  1663.                     result.NamespaceUri = XmlnsUri;
  1664.                 } else {
  1665.                     result.NamespaceUri = context.GetNamespaceOfPrefix(prefix);
  1666.                 }
  1667.             } else {
  1668.                 result.Prefix = "";
  1669.                 result.LocalName = name;
  1670.                 if (name == "xmlns") {
  1671.                     result.NamespaceUri = XmlnsUri;
  1672.                 } else if (nt == XmlNodeType.Attribute) {
  1673.                     result.NamespaceUri = ""; // non-prefixed attributes are empty namespace by definition
  1674.                 } else {
  1675.                     result.NamespaceUri = context.GetNamespaceOfPrefix("");
  1676.                 }
  1677.             }
  1678.             return result;
  1679.         }
  1680.         public static XmlName ParseName(XmlNamespaceManager nsmgr, string name, XmlNodeType nt) {
  1681.             XmlName result = new XmlName();
  1682.             XmlConvert.VerifyName(name);
  1683.             int i = name.IndexOf(':');
  1684.             if (i > 0) {
  1685.                 string prefix = result.Prefix = name.Substring(0, i);
  1686.                 result.LocalName = name.Substring(i + 1);
  1687.                 if (prefix == "xml") {
  1688.                     result.NamespaceUri = XmlUri;
  1689.                 } else if (prefix == "xmlns") {
  1690.                     result.NamespaceUri = XmlnsUri;
  1691.                 } else {
  1692.                     result.NamespaceUri = nsmgr.LookupNamespace(prefix);
  1693.                 }
  1694.             } else {
  1695.                 result.LocalName = name;
  1696.                 if (name == "xmlns") {
  1697.                     result.NamespaceUri = XmlnsUri;
  1698.                 } else if (nt == XmlNodeType.Attribute) {
  1699.                     result.NamespaceUri = ""; // non-prefixed attributes are empty namespace by definition
  1700.                 } else {
  1701.                     result.NamespaceUri = nsmgr.LookupNamespace("");
  1702.                 }
  1703.             }
  1704.             return result;
  1705.         }
  1706.         public static XmlNamespaceManager GetNamespaceScope(XmlNode context){
  1707.             XmlDocument owner = null;
  1708.             if (context is XmlDocument) {
  1709.                 owner = (XmlDocument)context;
  1710.             } else {
  1711.                 owner = context.OwnerDocument;
  1712.             }
  1713.             XmlNameTable nt = owner.NameTable;
  1714.             XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
  1715.             XmlNode parent = context;
  1716.             while (parent != null) {
  1717.                 if (parent is XmlElement){
  1718.                     if (parent.Attributes != null) {
  1719.                         foreach (XmlAttribute a in parent.Attributes) {
  1720.                             if (a.NamespaceURI == XmlnsUri) {
  1721.                                 string prefix = nt.Add(a.LocalName);
  1722.                                 if (prefix == "xmlns") prefix = "";
  1723.                                 if (!nsmgr.HasNamespace(prefix)) {
  1724.                                     nsmgr.AddNamespace(prefix, nt.Add(a.Value));
  1725.                                 }
  1726.                             }
  1727.                         }
  1728.                     }
  1729.                 }
  1730.                 parent = parent.ParentNode;
  1731.             }
  1732.             return nsmgr;
  1733.         }
  1734.         public static bool MissingNamespace(XmlName name) {
  1735.             return !string.IsNullOrEmpty(name.Prefix) && string.IsNullOrEmpty(name.NamespaceUri) &&
  1736.                 name.Prefix != "xmlns" && name.LocalName != "xmlns" && name.Prefix != "xml";
  1737.         }
  1738.         public static XmlAttribute GenerateNamespaceDeclaration(XmlElement context, XmlName name) {
  1739.             int count = 1;
  1740.             while (!string.IsNullOrEmpty(context.GetPrefixOfNamespace("uri:" + count))) {
  1741.                 count++;
  1742.             }
  1743.             name.NamespaceUri = "uri:" + count;
  1744.             XmlAttribute xmlns = context.OwnerDocument.CreateAttribute("xmlns", name.Prefix, XmlHelpers.XmlnsUri);
  1745.             if (context.HasAttribute(xmlns.Name)) {
  1746.                 // already have an attribute with this name! This is a tricky case where
  1747.                 // user is deleting a namespace declaration.  We don't want to reinsert it
  1748.                 // automatically in that case!
  1749.                 return null;
  1750.             }
  1751.             xmlns.Value = name.NamespaceUri;
  1752.             return xmlns;
  1753.         }
  1754.         public static bool IsXmlnsNode(XmlNode node) {
  1755.             if (node == null) return false;
  1756.             return node.NodeType == XmlNodeType.Attribute &&
  1757.                 (node.LocalName == "xmlns" || node.Prefix == "xmlns");
  1758.         }
  1759.         public static bool IsXsiAttribute(XmlNode node) {
  1760.             if (node == null) return false;
  1761.             return node.NodeType == XmlNodeType.Attribute &&
  1762.                 (node.LocalName == "type" && node.NamespaceURI == "http://www.w3.org/2001/XMLSchema-instance");
  1763.         }
  1764.     }
  1765. }