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

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Xml;
  4. using System.Windows.Forms;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Diagnostics;
  8. using System.ComponentModel;
  9. using System.Text;
  10. namespace XmlNotepad {
  11.     //========================================================================================
  12.     /// <summary>
  13.     /// Displays the text of the attributes, comments, text, cdata and leaf element nodes and 
  14.     /// provides type-to-find and editing of those values.
  15.     /// </summary>
  16.     public class NodeTextView : UserControl, IEditableView {
  17.         Dictionary<TreeNode, string> visibleTextCache;  
  18.         private Color containerBackground = Color.AliceBlue;
  19.         private TreeNode selectedNode;
  20.         Settings settings;
  21.         private TypeToFindHandler ttf;
  22.         Point scrollPosition;
  23.         private TextEditorOverlay editor;
  24.         private TreeNodeCollection nodes;
  25.         public event EventHandler<TreeViewEventArgs> AfterSelect;
  26.         /// <summary> 
  27.         /// Required designer variable.
  28.         /// </summary>
  29.         private System.ComponentModel.IContainer components = null;
  30.         public NodeTextView() {
  31.             this.SetStyle(ControlStyles.ResizeRedraw,true);
  32.             this.SetStyle(ControlStyles.UserPaint,true);
  33.             this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
  34.             this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
  35.             this.SetStyle(ControlStyles.Selectable,true);
  36.           
  37.             InitializeComponent();
  38.             this.SuspendLayout();
  39.             this.editor = new TextEditorOverlay(this);
  40.             this.editor.MultiLine = true;
  41.             this.editor.CommitEdit += new EventHandler<TextEditorEventArgs>(OnCommitEdit);
  42.             this.editor.LayoutEditor += new EventHandler<TextEditorLayoutEventArgs>(OnLayoutEditor);
  43.             this.ttf = new TypeToFindHandler(this, 2000);
  44.             this.ttf.FindString += new TypeToFindEventHandler(FindString);
  45.             this.ResumeLayout();
  46.             this.AccessibleRole=System.Windows.Forms.AccessibleRole.List;
  47.             visibleTextCache = new Dictionary<TreeNode, string>();
  48.         }
  49.         #region Component Designer generated code
  50.         /// <summary> 
  51.         /// Clean up any resources being used.
  52.         /// </summary>
  53.         /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  54.         protected override void Dispose(bool disposing) {
  55.             if (disposing && (components != null)) {
  56.                 components.Dispose();
  57.             }
  58.             if (this.ttf != null) {
  59.                 this.ttf.Dispose();
  60.                 this.ttf = null;
  61.             }
  62.             base.Dispose(disposing);
  63.         }
  64.         /// <summary> 
  65.         /// Required method for Designer support - do not modify 
  66.         /// the contents of this method with the code editor.
  67.         /// </summary>
  68.         private void InitializeComponent() {
  69.             this.components = new System.ComponentModel.Container();
  70.             this.SuspendLayout();
  71.             this.AccessibleRole = AccessibleRole.List;
  72.             this.Name = this.AccessibleName = "NodeTextView";
  73.             this.AccessibleDescription = "Right hand side of the XmlTreeView for editing node values";
  74.             this.ResumeLayout(false);
  75.         }
  76.         #endregion
  77.         public void Close() {
  78.             this.editor.Dispose();
  79.             ClearCache();
  80.         }
  81.         void ClearCache() {
  82.             if (visibleTextCache != null)
  83.                 visibleTextCache.Clear();
  84.         }
  85.         // The nodes to display.
  86.         public TreeNodeCollection Nodes {
  87.             get { return this.nodes; }
  88.             set {
  89.                 this.selectedNode = null;
  90.                 this.nodes = value;
  91.                 ClearCache();
  92.                 PerformLayout();
  93.             }
  94.         }
  95.         [System.ComponentModel.Browsable(false)]
  96.         public UndoManager UndoManager {
  97.             get { return (UndoManager)this.Site.GetService(typeof(UndoManager)); }
  98.         }
  99.         [System.ComponentModel.Browsable(false)]
  100.         public IIntellisenseProvider IntellisenseProvider {
  101.             get { return (IIntellisenseProvider)this.Site.GetService(typeof(IIntellisenseProvider)); }
  102.         }
  103.         public void SetSite(ISite site) {
  104.             // Overriding the Site property directly breaks the WinForms designer.
  105.             this.Site = site;
  106.             this.settings = (Settings)site.GetService(typeof(Settings));
  107.             if (this.settings != null) {
  108.                 this.settings.Changed += new SettingsEventHandler(settings_Changed);
  109.             }
  110.             settings_Changed(this, "");
  111.             this.editor.Site = site;
  112.             XmlCache model = (XmlCache)site.GetService(typeof(XmlCache));
  113.             model.ModelChanged += new EventHandler<ModelChangedEventArgs>(OnModelChanged);
  114.         }
  115.         void OnModelChanged(object sender, ModelChangedEventArgs e) {
  116.             ClearCache();
  117.         }
  118.         public Point ScrollPosition {
  119.             get { return this.scrollPosition; }
  120.             set { this.scrollPosition = value; }
  121.         }
  122.         public Point ApplyScrollOffset(int x, int y) {
  123.             return new Point(x - this.scrollPosition.X, y - this.scrollPosition.Y);
  124.         }
  125.         public Point ApplyScrollOffset(Point pt) {
  126.             return new Point(pt.X - this.scrollPosition.X, pt.Y - this.scrollPosition.Y);
  127.         }
  128.         private void settings_Changed(object sender, string name) {
  129.             // change the colors.
  130.             Invalidate();
  131.             if (this.settings != null) {
  132.                 System.Collections.Hashtable colors = (System.Collections.Hashtable)this.settings["Colors"];
  133.                 if (colors != null) {
  134.                     object color = colors["ContainerBackground"];
  135.                     if (color != null) {
  136.                         this.containerBackground = (Color)color;
  137.                     }
  138.                 }
  139.             }
  140.         }
  141.         protected override void OnGotFocus(EventArgs e) {
  142.             if (this.selectedNode != null){
  143.                 Invalidate(this.selectedNode);
  144.             }
  145.             base.OnGotFocus (e);
  146.         }
  147.         protected override void OnLostFocus(EventArgs e) {
  148.             if (this.selectedNode != null){
  149.                 Invalidate(this.selectedNode);
  150.             }
  151.             base.OnLostFocus (e);
  152.         }
  153.         public void Reset(){
  154.             this.editor.EndEdit(false);
  155.             this.selectedNode = null;
  156.             Invalidate();
  157.         }
  158.         public TreeNode SelectedNode {
  159.             get { return this.selectedNode; }
  160.             set {
  161.                 if (this.selectedNode != value) {
  162.                     this.editor.EndEdit(false);
  163.                     InternalSelect(value);
  164.                     if (AfterSelect != null) {
  165.                         AfterSelect(this, new TreeViewEventArgs(value, TreeViewAction.None));
  166.                     }
  167.                 }
  168.             }
  169.         }
  170.         internal void InternalSelect(TreeNode node) {
  171.             this.selectedNode = node;
  172.             Invalidate();
  173.         }
  174.         static bool IsTextEditable(TreeNode node) {
  175.             NodeImage img = (NodeImage)(node.ImageIndex+1);
  176.             return !(img == NodeImage.Element || img == NodeImage.OpenElement);
  177.         }
  178.         protected override void OnMove(EventArgs e) {
  179.             this.editor.EndEdit(false);
  180.             base.OnMove (e);
  181.         }
  182.         
  183.         protected override void OnLayout(LayoutEventArgs levent) {
  184.             base.OnLayout (levent);
  185.             ClearCache(); 
  186.             if (this.editor.IsEditing) {
  187.                 this.editor.PerformLayout();
  188.             }
  189.         }
  190.         void OnLayoutEditor(object sender, TextEditorLayoutEventArgs args) {
  191.             Rectangle r = this.GetTextBounds(this.selectedNode);
  192.             r.Offset(this.scrollPosition);
  193.             args.PreferredBounds = r;
  194.             args.MaxBounds = r;
  195.         }
  196.         string CheckTextLength(string text, out bool cancelled) {
  197.             cancelled = false;
  198.             if (text == null) return "";
  199.             int maxLine = GetMaxLineLength(text);
  200.             if (maxLine > 10000) {
  201.                 DialogResult rc = MessageBox.Show(this, SR.LongLinePrompt, SR.LongLineCaption,
  202.                     MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation);
  203.                 if (rc == DialogResult.Cancel) {
  204.                     cancelled = true;
  205.                     return text;
  206.                 }
  207.                 if (rc == DialogResult.No) {
  208.                     return text;
  209.                 }
  210.                 return FormatLines(text);
  211.             }
  212.             return text;
  213.         }
  214.         private static string FormatLines(string text) {
  215.             StringBuilder sb = new StringBuilder();
  216.             int lineStart = 0;
  217.             int j = 0;
  218.             for (int i = 0, len = text.Length; i < len; i++) {
  219.                 char c = text[i];
  220.                 bool lineEnd = false;
  221.                 if (c == 'r') {
  222.                     if (i + 1 < len && text[i + 1] == 'n') i++;
  223.                     lineEnd = true;
  224.                 } else if (c == 'n') {
  225.                     lineEnd = true;
  226.                 }
  227.                 if (lineEnd) {
  228.                     string line = text.Substring(lineStart, i + 1 - lineStart);
  229.                     sb.Append(line);
  230.                     lineStart = i+1;
  231.                     j = 0;
  232.                 } else if (++j == 80) {
  233.                     string line = text.Substring(lineStart, 80);
  234.                     sb.Append(line);
  235.                     sb.Append("rn");
  236.                     lineStart = i+1;
  237.                     j = 0;
  238.                 } else if (i + 1 == len) {
  239.                     string line = text.Substring(lineStart);
  240.                     sb.Append(line);
  241.                 }
  242.             }
  243.             return sb.ToString();
  244.         }
  245.         private static int GetMaxLineLength(string text) {
  246.             int maxLine = 0;
  247.             int lastLine = 0;
  248.             for (int i = 0, len = text.Length; i < len; i++) {
  249.                 char c = text[i];
  250.                 bool lineEnd = false;
  251.                 if (c == 'r') {
  252.                     if (i + 1 < len && text[i + 1] == 'n') i++;
  253.                     lineEnd = true;
  254.                 } else if (c == 'n') {
  255.                     lineEnd = true;
  256.                 }
  257.                 if (lineEnd || i+1==len) {
  258.                     int linelen = i - lastLine;
  259.                     lastLine = i+1;
  260.                     maxLine = Math.Max(maxLine, linelen);
  261.                 }
  262.             }
  263.             return maxLine;
  264.         }
  265.         public bool FocusBeginEdit(string value) {
  266.             this.Focus();
  267.             return BeginEdit(value);
  268.         }
  269.         #region IEditableView
  270.         public bool BeginEdit(string value) {
  271.             if (this.selectedNode != null) {
  272.                 if (string.IsNullOrEmpty(this.selectedNode.Label)) {
  273.                     MessageBox.Show(this, SR.NodeNameRequiredPrompt, SR.NodeNameRequiredCaption,
  274.                         MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
  275.                 } 
  276.                 else if (IsTextEditable(this.selectedNode)) {
  277.                     // see if control has possible values that cannot be known in xsd
  278.                     IIntellisenseProvider provider = this.IntellisenseProvider;
  279.                     string text = value != null ? value : GetNodeText(this.selectedNode);
  280.                     if (provider != null) {
  281.                         provider.SetContextNode(this.selectedNode);
  282.                         if (!provider.IsValueEditable) {
  283.                             return false;
  284.                         }                        
  285.                     }
  286.                     bool cancel = false;
  287.                     text = CheckTextLength(text, out cancel);
  288.                     if (cancel) return false;
  289.                     this.editor.BeginEdit(text, provider, EditMode.Value, this.selectedNode.ForeColor, this.Focused);
  290.                     return true;
  291.                 }
  292.             }
  293.             return false;
  294.         }
  295.         public bool IsEditing {
  296.             get { return this.editor.IsEditing; }
  297.         }
  298.         public void SelectText(int index, int length) {
  299.             if (this.editor.IsEditing) {
  300.                 this.editor.Select(index, length);
  301.             }
  302.         }
  303.         public bool ReplaceText(int index, int length, string replacement){
  304.             if (this.editor.IsEditing) {
  305.                 return this.editor.Replace(index, length, replacement);
  306.             }
  307.             return false;
  308.         }
  309.         public Rectangle EditorBounds {
  310.             get {
  311.                 return this.editor.Bounds;
  312.             }
  313.         }
  314.         public TextEditorOverlay Editor {
  315.             get { return this.editor; }
  316.         }
  317.         public bool EndEdit(bool cancel) {
  318.             return this.editor.EndEdit(cancel);
  319.         }
  320.         public int SelectionStart { get { return this.editor.SelectionStart; } }
  321.         public int SelectionLength { get { return this.editor.SelectionLength; } }
  322.         #endregion
  323.         void OnCommitEdit(object sender, TextEditorEventArgs args) {
  324.             if (!args.Cancelled) {
  325.                 SetNodeText(this.selectedNode, args.Text);
  326.             }
  327.         }
  328.         public void StartIncrementalSearch() {
  329.             ttf.StartIncrementalSearch();
  330.         }
  331.        
  332.         protected override bool IsInputKey(Keys keyData) {
  333.             Keys key = (keyData & ~Keys.Modifiers);
  334.             switch (key){
  335.                 case Keys.F2:
  336.                 case Keys.Enter:
  337.                 case Keys.Home:
  338.                 case Keys.End:
  339.                 case Keys.Up:
  340.                 case Keys.PageDown:
  341.                 case Keys.PageUp:
  342.                 case Keys.Right:
  343.                 case Keys.Left:
  344.                     return true;
  345.             }
  346.             return base.IsInputKey (keyData);
  347.         }
  348.         protected override void OnKeyDown(KeyEventArgs e) {
  349.             CurrentEvent.Event = e;
  350.             base.OnKeyDown(e);
  351.             if (!e.Handled) {
  352.                 HandleKeyDown(e);
  353.             }
  354.         }
  355.         public void BubbleKeyDown(KeyEventArgs e) {
  356.             base.OnKeyDown(e);
  357.         }
  358.         public void HandleKeyDown(KeyEventArgs e) {
  359.             bool isLetterOrDigit = ((e.KeyCode >= Keys.A && e.KeyCode <= Keys.Z) ||
  360.                        (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)) &&
  361.                        (e.Modifiers == Keys.Shift || e.Modifiers == 0);
  362.             switch (e.KeyCode) {
  363.                 case Keys.F2:
  364.                 case Keys.Enter:
  365.                     BeginEdit(null);
  366.                     e.Handled = true;
  367.                     break;
  368.                 case Keys.Left:
  369.                     // do not give to tree view, this will do a shift-tab instead.
  370.                     break;
  371.                 default:
  372.                     if (isLetterOrDigit && !e.Handled && this.ContainsFocus) {
  373.                         if (ttf.Started) {
  374.                             e.Handled = true; // let ttf handle it!
  375.                         } else {
  376.                             char ch = Convert.ToChar(e.KeyValue);
  377.                             if (!e.Shift) ch = Char.ToLower(ch);
  378.                             if (this.BeginEdit(ch.ToString())) {
  379.                                 this.editor.SelectEnd();
  380.                                 e.Handled = true;
  381.                             }
  382.                         }
  383.                     }
  384.                     break;
  385.             }
  386.         }
  387.         protected override void OnPaint(PaintEventArgs e) {
  388.             Rectangle clip = e.ClipRectangle;
  389.             Graphics g = e.Graphics;
  390.             Matrix m = g.Transform;
  391.             m.Translate(this.scrollPosition.X, this.scrollPosition.Y);
  392.             g.Transform = m;
  393.             base.OnPaint(e);
  394.             if (this.nodes != null){
  395.                 clip = new Rectangle(this.ApplyScrollOffset(clip.X, clip.Y), new Size(clip.Width, clip.Height));
  396.                 PaintNodes(this.nodes, g, ref clip);
  397.             }
  398.         }
  399.         void PaintNodes(TreeNodeCollection nodes, Graphics g, ref Rectangle clip) {
  400.             if (nodes == null) return;
  401.             g.SmoothingMode = SmoothingMode.AntiAlias;
  402.             foreach (TreeNode n in nodes) {
  403.                 Rectangle r = GetTextBounds(n);
  404.                 if (r.Top > clip.Bottom) return;
  405.                 if (r.IntersectsWith(clip)){
  406.                     DrawItem(r, n, g);
  407.                 }
  408.                 if (n.IsExpanded){
  409.                     PaintNodes(n.Nodes, g, ref clip);
  410.                 }
  411.             }
  412.         }
  413.         static string GetNodeText(TreeNode n) {
  414.             string text = n.Text;
  415.             return NormalizeNewLines(text);
  416.         }
  417.         public static string NormalizeNewLines(string text){
  418.             if (text == null) return null;
  419.             StringBuilder sb = new StringBuilder();
  420.             for (int i = 0, n = text.Length; i<n; i++){
  421.                 char ch = text[i];
  422.                 if (ch == 'r'){
  423.                     if (i+1<n && text[i+1] == 'n')
  424.                         i++;
  425.                     sb.Append("rn");
  426.                 } else if (ch == 'n'){
  427.                     sb.Append("rn");
  428.                 } else {
  429.                     sb.Append(ch);
  430.                 }
  431.             }
  432.             return sb.ToString();
  433.         }
  434.         static void SetNodeText(TreeNode n, string value) {
  435.             n.Text = value;
  436.         }
  437.         public void Invalidate(TreeNode n) {
  438.             if (n != null) {
  439.                 Rectangle r = this.GetTextBounds(n);
  440.                 r.Offset(this.scrollPosition);
  441.                 Invalidate(r);
  442.             }
  443.         }
  444.         private void DrawItem(Rectangle bounds, TreeNode tn, Graphics g) {
  445.             //g.SmoothingMode = SmoothingMode.AntiAlias;
  446.             Color c = tn.ForeColor;
  447.             Brush myBrush = null;
  448.             bool focusSelected = false;
  449.             if (this.Focused && tn == this.SelectedNode) {
  450.                 focusSelected = true;
  451.                 g.FillRectangle(SystemBrushes.Highlight, bounds);
  452.                 myBrush = Utilities.HighlightTextBrush(c);
  453.             } else {
  454.                 myBrush = new SolidBrush(c);
  455.             }
  456.             Font font = this.Font;
  457.             Rectangle inset = new Rectangle(bounds.Left + 3, bounds.Top, bounds.Width - 3, bounds.Height);
  458.             string value = null;
  459.             if (this.visibleTextCache.ContainsKey(tn)) {
  460.                 value = this.visibleTextCache[tn];
  461.             } else {
  462.                 value = GetNodeText(tn);
  463.             }
  464.             if (value == null && !focusSelected) {
  465.                 using (Brush b = new SolidBrush(containerBackground)) {
  466.                     g.FillRectangle(b, bounds);
  467.                 }
  468.             }
  469.             if (value != null && value.Length > 0) {
  470.                 //inset.Inflate(-3, -2);
  471.                 char ellipsis = Convert.ToChar(0x2026);
  472.                 value = value.Trim();
  473.                 int i = value.IndexOfAny(new char[] { 'r', 'n' });
  474.                 if (i > 0) {
  475.                     value = value.Substring(0, i) + ellipsis;
  476.                 }
  477.                 // Figure out how much of the text we can display                
  478.                 int width = inset.Width; ;
  479.                 //int height = inset.Height;
  480.                 string s = value;
  481.                 if (width < 0) return;
  482.                 int length = value.Length;
  483.                 SizeF size = SizeF.Empty;
  484.                 bool measurable = false;
  485.                 while (!measurable) {
  486.                     try {
  487.                         if (s.Length >= 65536) {
  488.                             // MeasureString tops out at 64kb strings.
  489.                             s = s.Substring(0, 65535);
  490.                         }
  491.                         size = g.MeasureString(s, font, width + 1000, StringFormat.GenericTypographic);
  492.                         measurable = true;
  493.                     } catch (Exception) {
  494.                         // perhaps the string is just too long!
  495.                         s = s.Substring(0, s.Length / 2);
  496.                     }
  497.                 }
  498.                 int j = s.Length;
  499.                 int dy = (font.Height - (int)Math.Ceiling(size.Height)) / 2;
  500.                 if (dy < 0) dy = 0;
  501.                 char[] ws = new char[] { ' ', 't' };
  502.                 if ((int)size.Width > width && j > 1) { // line wrap?
  503.                     int start = 0;
  504.                     int w = 0;
  505.                     int k = value.IndexOfAny(ws);
  506.                     while (k > 0) {
  507.                         s = value.Substring(0, k) + ellipsis;
  508.                         size = g.MeasureString(s, font, width + 1000, StringFormat.GenericTypographic);
  509.                         if ((int)size.Width < width && k < length) {
  510.                             start = k;
  511.                             w = (int)size.Width;
  512.                             while (start < length && (value[start] == ' ' || value[start] == 't')) {
  513.                                 start++;
  514.                             }
  515.                             k = value.IndexOfAny(ws, start);
  516.                         } else {
  517.                             break;
  518.                         }
  519.                     }
  520.                     j = start;
  521.                     if (w < width / 2) {
  522.                         // if we have a really long word (e.g. binhex) then just take characters
  523.                         // up to the end of the line.                        
  524.                         while ((int)w < width && j < length) {
  525.                             j++;
  526.                             s = value.Substring(0, j) + ellipsis;
  527.                             size = g.MeasureString(s, font, width + 1000, StringFormat.GenericTypographic);
  528.                             w = (int)size.Width;
  529.                         }
  530.                     }
  531.                     if (j <= 0) {
  532.                         s = "";
  533.                     } else if (j < length) {
  534.                         s = value.Substring(0, j - 1) + ellipsis;
  535.                     }
  536.                     this.visibleTextCache[tn] = s;
  537.                 }
  538.                 // Draw the current item text based on the current Font and the custom brush settings.
  539.                 g.DrawString(s, font, myBrush, inset.Left, dy + inset.Top, StringFormat.GenericTypographic);
  540.             }
  541.             // If the ListBox has focus, draw a focus rectangle around the selected item.
  542.             if (tn == this.SelectedNode) {
  543.                 g.SmoothingMode = SmoothingMode.Default;
  544.                 Pen p = new Pen(Color.Black, 1);
  545.                 p.DashStyle = DashStyle.Dot;
  546.                 p.Alignment = PenAlignment.Inset;
  547.                 p.LineJoin = LineJoin.Round;
  548.                 bounds.Width--;
  549.                 bounds.Height--;
  550.                 g.DrawRectangle(p, bounds);
  551.                 p.Dispose();
  552.             }
  553.             myBrush.Dispose();
  554.         }
  555.         protected override void OnMouseDown(MouseEventArgs e) {
  556.             base.OnMouseDown(e);
  557.             CurrentEvent.Event = e;
  558.             this.editor.EndEdit(false);
  559.             if (this.nodes != null) {
  560.                 Point p = this.ApplyScrollOffset(e.X, e.Y);
  561.                 TreeNode tn = this.FindNodeAt(this.nodes, p.X, p.Y);
  562.                 if (tn != null) {
  563.                     if (this.SelectedNode == tn && this.Focused) {
  564.                         if (e.Button == MouseButtons.Left) {
  565.                             this.BeginEdit(null);
  566.                         }
  567.                         return;
  568.                     } else {
  569.                         this.SelectedNode = tn;
  570.                     }
  571.                 }
  572.             }
  573.             this.Focus();        
  574.         }
  575.         public TreeNode FindNodeAt(TreeNodeCollection nodes, int x, int y) {
  576.             if (nodes == null) return null;
  577.             foreach (TreeNode n in nodes) {
  578.                 Rectangle r = GetTextBounds(n);
  579.                 if (r.Contains(x, y)) {
  580.                     return n;
  581.                 }
  582.                 if (n.IsExpanded && n.LabelBounds.Top <= y && n.bottom >= y) {
  583.                     TreeNode result = FindNodeAt(n.Nodes, x, y);
  584.                     if (result != null) return result;
  585.                 }
  586.             }
  587.             return null;
  588.         }
  589.         
  590.         public Rectangle GetTextBounds(TreeNode n) {
  591.             Rectangle r = new Rectangle(0, n.LabelBounds.Top, this.Width, n.LabelBounds.Height);
  592.             return r;
  593.         }
  594.         void FindString(object sender, string toFind) {
  595.             TreeNode node = this.SelectedNode;
  596.         
  597.             if (node == null) node = this.FirstVisibleNode;
  598.             TreeNode start = node;
  599.             while (node != null) {
  600.                 string s = GetNodeText(node);
  601.                 if (s != null && s.StartsWith(toFind, StringComparison.CurrentCultureIgnoreCase)) {
  602.                     this.SelectedNode = node;
  603.                     return;
  604.                 }
  605.                 node = node.NextVisibleNode;
  606.                 if (node == null) node = this.FirstVisibleNode;
  607.                 if (node == start)
  608.                     break;
  609.             }
  610.         }
  611.         public TreeNode FirstVisibleNode {
  612.             get {
  613.                 if (this.nodes == null) return null;
  614.                 foreach (TreeNode node in this.nodes) {
  615.                     if (node.IsVisible) {
  616.                         return node;
  617.                     }
  618.                 }
  619.                 return null;
  620.             }
  621.         }
  622.         AccessibleNodeTextView acc;
  623.         protected override AccessibleObject CreateAccessibilityInstance() {
  624.             if (this.acc == null) this.acc = new AccessibleNodeTextView(this);
  625.             return this.acc;
  626.         }
  627.     }
  628.     class AccessibleNodeTextView : Control.ControlAccessibleObject {
  629.         NodeTextView view;
  630.         Dictionary<TreeNode, AccessibleObject> cache = new Dictionary<TreeNode, AccessibleObject>();
  631.         public AccessibleNodeTextView(NodeTextView view)
  632.             : base(view) {
  633.             this.view = view;
  634.         }
  635.         public NodeTextView View { get { return this.view; } }
  636.         public override Rectangle Bounds {
  637.             get {
  638.                 return view.RectangleToScreen(view.ClientRectangle);
  639.             }
  640.         }
  641.         public override string DefaultAction {
  642.             get {
  643.                 return "Edit";
  644.             }
  645.         }
  646.         public override void DoDefaultAction() {
  647.             if (view.SelectedNode != null) {
  648.                 view.FocusBeginEdit(null);
  649.             }
  650.         }
  651.         public override int GetChildCount() {
  652.             return view.Nodes.Count;
  653.         }
  654.         public override AccessibleObject GetChild(int index) {
  655.             TreeNode node = view.Nodes[index];
  656.             return Wrap(node);
  657.         }
  658.         public AccessibleObject Wrap(TreeNode node) {
  659.             if (node == null) return null;
  660.             AccessibleObject a;
  661.             cache.TryGetValue(node, out a);
  662.             if (a == null){
  663.                 a = new AccessibleNodeTextViewNode(this, node);
  664.                 cache[node] = a;
  665.             }
  666.             return a;
  667.         }
  668.         public override AccessibleObject GetFocused() {
  669.             return GetSelected();
  670.         }
  671.         public override int GetHelpTopic(out string fileName) {
  672.             fileName = "TBD";
  673.             return 0;
  674.         }
  675.         public override AccessibleObject GetSelected() {
  676.             if (view.SelectedNode != null) {
  677.                 return Wrap(view.SelectedNode);
  678.             }
  679.             return this;
  680.         }
  681.         public override AccessibleObject HitTest(int x, int y) {
  682.             Point pt = view.PointToClient(new Point(x, y));
  683.             pt = view.ApplyScrollOffset(pt);
  684.             TreeNode node = view.FindNodeAt(view.Nodes, pt.X, pt.Y);
  685.             if (node != null) {
  686.                 return Wrap(node);
  687.             }
  688.             return this;
  689.         }
  690.         public override AccessibleObject Navigate(AccessibleNavigation navdir) {
  691.             TreeNode node = null;
  692.             TreeNodeCollection children = view.Nodes;
  693.             int count = children.Count;
  694.             switch (navdir) {
  695.                 case AccessibleNavigation.Left:
  696.                 case AccessibleNavigation.Down:
  697.                 case AccessibleNavigation.FirstChild:
  698.                     if (count > 0) node = children[0];
  699.                     break;
  700.                 case AccessibleNavigation.Next:
  701.                 case AccessibleNavigation.Previous:
  702.                 case AccessibleNavigation.Right:
  703.                 case AccessibleNavigation.Up:
  704.                     if (count > 0) node = children[count - 1];
  705.                     break;
  706.                 case AccessibleNavigation.LastChild:
  707.                     // special meaning for us, it means find the intellisense popup window!
  708.                     return view.Editor.CompletionSet.AccessibilityObject;                    
  709.             }
  710.             if (node != null) {
  711.                 return Wrap(node);
  712.             }
  713.             return this;
  714.         }
  715.         public override AccessibleObject Parent {
  716.             get {
  717.                 return view.Parent.AccessibilityObject;
  718.             }
  719.         }
  720.         public override AccessibleRole Role {
  721.             get {
  722.                 return view.AccessibleRole;
  723.             }
  724.         }
  725.         public override void Select(AccessibleSelection flags) {
  726.             this.view.Focus();
  727.         }
  728.         public override AccessibleStates State {
  729.             get {
  730.                 AccessibleStates result = AccessibleStates.Focusable | AccessibleStates.Selectable |
  731.                     AccessibleStates.Sizeable;
  732.                 if (view.Focused) result |= AccessibleStates.Focused;
  733.                 if (!view.Visible) result |= AccessibleStates.Invisible;
  734.                 return result;
  735.             }
  736.         }
  737.         public override string Value {
  738.             get {
  739.                 return "";
  740.             }
  741.             set {
  742.                 //???
  743.             }
  744.         }
  745.     }
  746.     class AccessibleNodeTextViewNode : AccessibleObject {
  747.         TreeNode node;
  748.         NodeTextView view;
  749.         AccessibleNodeTextView acc;
  750.         public AccessibleNodeTextViewNode(AccessibleNodeTextView acc, TreeNode node) {
  751.             this.acc = acc;
  752.             this.view = acc.View;
  753.             this.node = node;
  754.         }
  755.         public override Rectangle Bounds {
  756.             get {
  757.                 Rectangle bounds = view.GetTextBounds(node);
  758.                 bounds.Offset(view.ScrollPosition);
  759.                 return view.RectangleToScreen(bounds);
  760.             }
  761.         }
  762.         public override string DefaultAction {
  763.             get {
  764.                 return "Toggle";
  765.             }
  766.         }
  767.         public override string Description {
  768.             get {
  769.                 return "TextNode";
  770.             }
  771.         }
  772.         public override void DoDefaultAction() {
  773.             node.Toggle();
  774.         }
  775.         public override int GetChildCount() {
  776.             return node.Nodes.Count;
  777.         }
  778.         public override AccessibleObject GetChild(int index) {
  779.             TreeNode child = this.node.Nodes[index];
  780.             return acc.Wrap(child);
  781.         }
  782.         public override AccessibleObject GetFocused() {
  783.             return GetSelected();
  784.         }
  785.         public override int GetHelpTopic(out string fileName) {
  786.             fileName = "TBD";
  787.             return 0;
  788.         }
  789.         public override AccessibleObject GetSelected() {
  790.             if (node.Selected) {
  791.                 return this;
  792.             }
  793.             return acc.GetSelected();
  794.         }
  795.         public override string Help {
  796.             get {
  797.                 return "TBD";
  798.             }
  799.         }
  800.         public override AccessibleObject HitTest(int x, int y) {
  801.             return acc.HitTest(x, y);
  802.         }
  803.         public override string KeyboardShortcut {
  804.             get {
  805.                 return "TBD";
  806.             }
  807.         }
  808.         public override string Name {
  809.             get {
  810.                 return node.Label;
  811.             }
  812.             set {
  813.                 // hack alert - this is breaking architectural layering!
  814.                 XmlTreeNode xnode = (XmlTreeNode)node;
  815.                 view.UndoManager.Push(new EditNodeName(xnode, value));
  816.             }
  817.         }
  818.         public override AccessibleObject Navigate(AccessibleNavigation navdir) {
  819.             TreeNode result = null;
  820.             TreeNodeCollection children = node.Nodes;
  821.             int count = children.Count;
  822.             switch (navdir) {
  823.                 case AccessibleNavigation.Down:
  824.                 case AccessibleNavigation.Next:
  825.                     result = node.NextVisibleNode;
  826.                     if (result == null) {
  827.                         return view.Editor.CompletionSet.AccessibilityObject;
  828.                     }
  829.                     break;
  830.                 case AccessibleNavigation.FirstChild:
  831.                     if (count > 0) result = children[0];
  832.                     if (!node.IsExpanded) node.Expand();
  833.                     break;
  834.                 case AccessibleNavigation.Left:
  835.                     return node.AccessibleObject;
  836.                 case AccessibleNavigation.Right:
  837.                     break;
  838.                 case AccessibleNavigation.LastChild:
  839.                     if (count > 0) result = children[count - 1];
  840.                     if (!node.IsExpanded) node.Expand();
  841.                     break;
  842.                 case AccessibleNavigation.Previous:
  843.                 case AccessibleNavigation.Up:
  844.                     result = node.PrevVisibleNode;
  845.                     break;
  846.             }
  847.             if (result != null) {
  848.                 return acc.Wrap(result);
  849.             }
  850.             return this;
  851.         }
  852.         public override AccessibleObject Parent {
  853.             get {
  854.                 if (node.Parent != null) {
  855.                     return acc.Wrap(node.Parent);
  856.                 } else {
  857.                     return acc;
  858.                 }
  859.             }
  860.         }
  861.         public override AccessibleRole Role {
  862.             get {
  863.                 return AccessibleRole.ListItem;
  864.             }
  865.         }
  866.         public override void Select(AccessibleSelection flags) {
  867.             view.Focus();
  868.             if ((flags & AccessibleSelection.TakeSelection) != 0 ||
  869.                 (flags & AccessibleSelection.AddSelection) != 0) {
  870.                 view.SelectedNode = node;
  871.             } else if ((flags & AccessibleSelection.RemoveSelection) != 0) {
  872.                 if (view.SelectedNode == this.node) {
  873.                     view.SelectedNode = null;
  874.                 }
  875.             }
  876.         }
  877.         public override AccessibleStates State {
  878.             get {
  879.                 AccessibleStates result = AccessibleStates.Focusable | AccessibleStates.Selectable;
  880.                 if (node.Selected) result |= AccessibleStates.Focused | AccessibleStates.Selected;
  881.                 if (!node.IsVisible) result |= AccessibleStates.Invisible | AccessibleStates.Collapsed;
  882.                 else result |= AccessibleStates.Expanded;
  883.                 return result;
  884.             }
  885.         }
  886.         public override string Value {
  887.             get {
  888.                 string s = this.node.Text;
  889.                 if (s == null) s = "";
  890.                 return s;
  891.             }
  892.             set {
  893.                 // hack alert - this is breaking architectural layering!
  894.                 XmlTreeNode xnode = (XmlTreeNode)node;
  895.                 XmlTreeView xview = xnode.XmlTreeView;
  896.                 view.UndoManager.Push(new EditNodeValue(xview, xnode, value));
  897.             }
  898.         }
  899.     }
  900. }