[mapguide-commits] r7850 - in trunk/Tools/Maestro: Maestro.Base/Editor Maestro.Editors Maestro.Editors/Generic Maestro.Editors/Generic/XmlEditor Maestro.Editors/Generic/XmlEditor/AutoCompletion

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Sep 6 10:39:33 PDT 2013


Author: jng
Date: 2013-09-06 10:39:32 -0700 (Fri, 06 Sep 2013)
New Revision: 7850

Added:
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedName.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedNameCollection.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionData.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataCollection.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataProvider.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlElementPath.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlParser.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaAssociation.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionData.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionDataCollection.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaManager.cs
Modified:
   trunk/Tools/Maestro/Maestro.Base/Editor/XmlEditor.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditorCtrl.cs
   trunk/Tools/Maestro/Maestro.Editors/Generic/XmlTextEditorControl.cs
   trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj
Log:
#2360: Add support for auto-completion of XML schema elements. This is grafted from the XML addin in SharpDevelop 3.2.1.

Modified: trunk/Tools/Maestro/Maestro.Base/Editor/XmlEditor.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Editor/XmlEditor.cs	2013-09-06 17:36:14 UTC (rev 7849)
+++ trunk/Tools/Maestro/Maestro.Base/Editor/XmlEditor.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -70,6 +70,8 @@
 
             _edSvc = service;
             _edSvc.RegisterCustomNotifier(editor);
+            var path = Path.Combine(this.XsdPath, _edSvc.GetEditedResource().ValidatingSchema);
+            editor.LoadAutoCompletionData(path);
             editor.Bind(_edSvc);
             editor.ReadyForEditing(); //This turns on event broadcasting
             this.Title = Strings.XmlEditor + " " + ResourceIdentifier.GetName(this.EditorService.ResourceID); //NOXLATE


Property changes on: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion
___________________________________________________________________
Added: bugtraq:number
   + true

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedName.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedName.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedName.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,167 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// An <see cref="XmlQualifiedName"/> with the namespace prefix.
+    /// </summary>
+    /// <remarks>
+    /// The namespace prefix active for a namespace is 
+    /// needed when an element is inserted via autocompletion. This
+    /// class just adds this extra information alongside the 
+    /// <see cref="XmlQualifiedName"/>.
+    /// </remarks>
+    public class QualifiedName
+    {
+        XmlQualifiedName xmlQualifiedName = XmlQualifiedName.Empty;
+        string prefix = String.Empty;
+
+        public QualifiedName()
+        {
+        }
+
+        public QualifiedName(string name, string namespaceUri)
+            : this(name, namespaceUri, String.Empty)
+        {
+        }
+
+        public QualifiedName(string name, string namespaceUri, string prefix)
+        {
+            xmlQualifiedName = new XmlQualifiedName(name, namespaceUri);
+            this.prefix = prefix;
+        }
+
+        public static bool operator ==(QualifiedName lhs, QualifiedName rhs)
+        {
+            bool equals = false;
+
+            if (((object)lhs != null) && ((object)rhs != null))
+            {
+                equals = lhs.Equals(rhs);
+            }
+            else if (((object)lhs == null) && ((object)rhs == null))
+            {
+                equals = true;
+            }
+
+            return equals;
+        }
+
+        public static bool operator !=(QualifiedName lhs, QualifiedName rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        /// <summary>
+        /// A qualified name is considered equal if the namespace and 
+        /// name are the same.  The prefix is ignored.
+        /// </summary>
+        public override bool Equals(object obj)
+        {
+            bool equals = false;
+
+            QualifiedName qualifiedName = obj as QualifiedName;
+            if (qualifiedName != null)
+            {
+                equals = xmlQualifiedName.Equals(qualifiedName.xmlQualifiedName);
+            }
+            else
+            {
+                XmlQualifiedName name = obj as XmlQualifiedName;
+                if (name != null)
+                {
+                    equals = xmlQualifiedName.Equals(name);
+                }
+            }
+
+            return equals;
+        }
+
+        public override int GetHashCode()
+        {
+            return xmlQualifiedName.GetHashCode();
+        }
+
+        /// <summary>
+        /// Gets the namespace of the qualified name.
+        /// </summary>
+        public string Namespace
+        {
+            get { return xmlQualifiedName.Namespace; }
+            set { xmlQualifiedName = new XmlQualifiedName(xmlQualifiedName.Name, value); }
+        }
+
+        /// <summary>
+        /// Gets the name of the element.
+        /// </summary>
+        public string Name
+        {
+            get { return xmlQualifiedName.Name; }
+            set { xmlQualifiedName = new XmlQualifiedName(value, xmlQualifiedName.Namespace); }
+        }
+
+        /// <summary>
+        /// Gets the namespace prefix used.
+        /// </summary>
+        public string Prefix
+        {
+            get { return prefix; }
+            set { prefix = value; }
+        }
+
+        /// <summary>
+        /// Returns a string that represents the QualifiedName.
+        /// </summary>
+        public override string ToString()
+        {
+            if (xmlQualifiedName.Namespace.Length > 0)
+            {
+                string prefixToString = String.Empty;
+                if (!String.IsNullOrEmpty(prefix))
+                {
+                    prefixToString = prefix + ":";
+                }
+                return String.Concat(prefixToString, xmlQualifiedName.Name, " [", xmlQualifiedName.Namespace, "]");
+            }
+            else if (!String.IsNullOrEmpty(prefix))
+            {
+                return prefix + ":" + xmlQualifiedName.Name;
+            }
+            return xmlQualifiedName.Name;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedNameCollection.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedNameCollection.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/QualifiedNameCollection.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,310 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    ///   A collection that stores <see cref='QualifiedName'/> objects.
+    /// </summary>
+    [Serializable()]
+    public class QualifiedNameCollection : CollectionBase
+    {
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        public QualifiedNameCollection()
+        {
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='QualifiedNameCollection'/> based on another <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///   A <see cref='QualifiedNameCollection'/> from which the contents are copied
+        /// </param>
+        public QualifiedNameCollection(QualifiedNameCollection val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='QualifiedNameCollection'/> containing any array of <see cref='QualifiedName'/> objects.
+        /// </summary>
+        /// <param name='val'>
+        ///       A array of <see cref='QualifiedName'/> objects with which to intialize the collection
+        /// </param>
+        public QualifiedNameCollection(QualifiedName[] val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Represents the entry at the specified index of the <see cref='QualifiedName'/>.
+        /// </summary>
+        /// <param name='index'>The zero-based index of the entry to locate in the collection.</param>
+        /// <value>The entry at the specified index of the collection.</value>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='index'/> is outside the valid range of indexes for the collection.</exception>
+        public QualifiedName this[int index]
+        {
+            get
+            {
+                return ((QualifiedName)(List[index]));
+            }
+            set
+            {
+                List[index] = value;
+            }
+        }
+
+        /// <summary>
+        ///   Adds a <see cref='QualifiedName'/> with the specified value to the 
+        ///   <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='QualifiedName'/> to add.</param>
+        /// <returns>The index at which the new element was inserted.</returns>
+        /// <seealso cref='QualifiedNameCollection.AddRange'/>
+        public int Add(QualifiedName val)
+        {
+            return List.Add(val);
+        }
+
+        /// <summary>
+        ///   Copies the elements of an array to the end of the <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///    An array of type <see cref='QualifiedName'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='QualifiedNameCollection.Add'/>
+        public void AddRange(QualifiedName[] val)
+        {
+            for (int i = 0; i < val.Length; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Adds the contents of another <see cref='QualifiedNameCollection'/> to the end of the collection.
+        /// </summary>
+        /// <param name='val'>
+        ///    A <see cref='QualifiedNameCollection'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='QualifiedNameCollection.Add'/>
+        public void AddRange(QualifiedNameCollection val)
+        {
+            for (int i = 0; i < val.Count; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Gets a value indicating whether the 
+        ///    <see cref='QualifiedNameCollection'/> contains the specified <see cref='QualifiedName'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='QualifiedName'/> to locate.</param>
+        /// <returns>
+        /// <see langword='true'/> if the <see cref='QualifiedName'/> is contained in the collection; 
+        ///   otherwise, <see langword='false'/>.
+        /// </returns>
+        /// <seealso cref='QualifiedNameCollection.IndexOf'/>
+        public bool Contains(QualifiedName val)
+        {
+            return List.Contains(val);
+        }
+
+        /// <summary>
+        ///   Copies the <see cref='QualifiedNameCollection'/> values to a one-dimensional <see cref='Array'/> instance at the 
+        ///    specified index.
+        /// </summary>
+        /// <param name='array'>The one-dimensional <see cref='Array'/> that is the destination of the values copied from <see cref='QualifiedNameCollection'/>.</param>
+        /// <param name='index'>The index in <paramref name='array'/> where copying begins.</param>
+        /// <exception cref='ArgumentException'>
+        ///   <para><paramref name='array'/> is multidimensional.</para>
+        ///   <para>-or-</para>
+        ///   <para>The number of elements in the <see cref='QualifiedNameCollection'/> is greater than
+        ///         the available space between <paramref name='arrayIndex'/> and the end of
+        ///         <paramref name='array'/>.</para>
+        /// </exception>
+        /// <exception cref='ArgumentNullException'><paramref name='array'/> is <see langword='null'/>. </exception>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='arrayIndex'/> is less than <paramref name='array'/>'s lowbound. </exception>
+        /// <seealso cref='Array'/>
+        public void CopyTo(QualifiedName[] array, int index)
+        {
+            List.CopyTo(array, index);
+        }
+
+        /// <summary>
+        ///    Returns the index of a <see cref='QualifiedName'/> in 
+        ///       the <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='QualifiedName'/> to locate.</param>
+        /// <returns>
+        ///   The index of the <see cref='QualifiedName'/> of <paramref name='val'/> in the 
+        ///   <see cref='QualifiedNameCollection'/>, if found; otherwise, -1.
+        /// </returns>
+        /// <seealso cref='QualifiedNameCollection.Contains'/>
+        public int IndexOf(QualifiedName val)
+        {
+            return List.IndexOf(val);
+        }
+
+        /// <summary>
+        ///   Inserts a <see cref='QualifiedName'/> into the <see cref='QualifiedNameCollection'/> at the specified index.
+        /// </summary>
+        /// <param name='index'>The zero-based index where <paramref name='val'/> should be inserted.</param>
+        /// <param name='val'>The <see cref='QualifiedName'/> to insert.</param>
+        /// <seealso cref='QualifiedNameCollection.Add'/>
+        public void Insert(int index, QualifiedName val)
+        {
+            List.Insert(index, val);
+        }
+
+        /// <summary>
+        ///  Returns an enumerator that can iterate through the <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        public new QualifiedNameEnumerator GetEnumerator()
+        {
+            return new QualifiedNameEnumerator(this);
+        }
+
+        /// <summary>
+        ///   Removes a specific <see cref='QualifiedName'/> from the <see cref='QualifiedNameCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='QualifiedName'/> to remove from the <see cref='QualifiedNameCollection'/>.</param>
+        /// <exception cref='ArgumentException'><paramref name='val'/> is not found in the Collection.</exception>
+        public void Remove(QualifiedName val)
+        {
+            List.Remove(val);
+        }
+
+        /// <summary>
+        /// Removes the last item in this collection.
+        /// </summary>
+        public void RemoveLast()
+        {
+            if (Count > 0)
+            {
+                RemoveAt(Count - 1);
+            }
+        }
+
+        /// <summary>
+        /// Removes the first item in the collection.
+        /// </summary>
+        public void RemoveFirst()
+        {
+            if (Count > 0)
+            {
+                RemoveAt(0);
+            }
+        }
+
+        /// <summary>
+        /// Gets the namespace prefix of the last item.
+        /// </summary>
+        public string LastPrefix
+        {
+            get
+            {
+                if (Count > 0)
+                {
+                    QualifiedName name = this[Count - 1];
+                    return name.Prefix;
+                }
+                return String.Empty;
+            }
+        }
+
+        /// <summary>
+        ///   Enumerator that can iterate through a QualifiedNameCollection.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        /// <seealso cref='QualifiedNameCollection'/>
+        /// <seealso cref='QualifiedName'/>
+        public class QualifiedNameEnumerator : IEnumerator
+        {
+            IEnumerator baseEnumerator;
+            IEnumerable temp;
+
+            /// <summary>
+            ///   Initializes a new instance of <see cref='QualifiedNameEnumerator'/>.
+            /// </summary>
+            public QualifiedNameEnumerator(QualifiedNameCollection mappings)
+            {
+                this.temp = ((IEnumerable)(mappings));
+                this.baseEnumerator = temp.GetEnumerator();
+            }
+
+            /// <summary>
+            ///   Gets the current <see cref='QualifiedName'/> in the <seealso cref='QualifiedNameCollection'/>.
+            /// </summary>
+            public QualifiedName Current
+            {
+                get
+                {
+                    return ((QualifiedName)(baseEnumerator.Current));
+                }
+            }
+
+            object IEnumerator.Current
+            {
+                get
+                {
+                    return baseEnumerator.Current;
+                }
+            }
+
+            /// <summary>
+            ///   Advances the enumerator to the next <see cref='QualifiedName'/> of the <see cref='QualifiedNameCollection'/>.
+            /// </summary>
+            public bool MoveNext()
+            {
+                return baseEnumerator.MoveNext();
+            }
+
+            /// <summary>
+            ///   Sets the enumerator to its initial position, which is before the first element in the <see cref='QualifiedNameCollection'/>.
+            /// </summary>
+            public void Reset()
+            {
+                baseEnumerator.Reset();
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionData.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionData.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionData.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,145 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using ICSharpCode.TextEditor;
+using ICSharpCode.TextEditor.Gui.CompletionWindow;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Holds the text for  namespace, child element or attribute 
+    /// autocomplete (intellisense).
+    /// </summary>
+    internal class XmlCompletionData : ICompletionData
+    {
+        string text;
+        DataType dataType = DataType.XmlElement;
+        string description = String.Empty;
+
+        /// <summary>
+        /// The type of text held in this object.
+        /// </summary>
+        public enum DataType
+        {
+            XmlElement = 1,
+            XmlAttribute = 2,
+            NamespaceUri = 3,
+            XmlAttributeValue = 4
+        }
+
+        public XmlCompletionData(string text)
+            : this(text, String.Empty, DataType.XmlElement)
+        {
+        }
+
+        public XmlCompletionData(string text, string description)
+            : this(text, description, DataType.XmlElement)
+        {
+        }
+
+        public XmlCompletionData(string text, DataType dataType)
+            : this(text, String.Empty, dataType)
+        {
+        }
+
+        public XmlCompletionData(string text, string description, DataType dataType)
+        {
+            this.text = text;
+            this.description = description;
+            this.dataType = dataType;
+        }
+
+        public int ImageIndex
+        {
+            get
+            {
+                return 0;
+            }
+        }
+
+        public string Text
+        {
+            get
+            {
+                return text;
+            }
+            set
+            {
+                text = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns the xml item's documentation as retrieved from
+        /// the xs:annotation/xs:documentation element.
+        /// </summary>
+        public string Description
+        {
+            get
+            {
+                return description;
+            }
+        }
+
+        public double Priority
+        {
+            get
+            {
+                return 0;
+            }
+        }
+
+        public bool InsertAction(TextArea textArea, char ch)
+        {
+            if ((dataType == DataType.XmlElement) || (dataType == DataType.XmlAttributeValue))
+            {
+                textArea.InsertString(text);
+            }
+            else if (dataType == DataType.NamespaceUri)
+            {
+                textArea.InsertString(String.Concat("\"", text, "\""));
+            }
+            else
+            {
+                // Insert an attribute.
+                Caret caret = textArea.Caret;
+                textArea.InsertString(String.Concat(text, "=\"\""));
+
+                // Move caret into the middle of the attribute quotes.
+                caret.Position = textArea.Document.OffsetToPosition(caret.Offset - 1);
+            }
+            return false;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataCollection.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataCollection.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataCollection.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,330 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using ICSharpCode.TextEditor.Gui.CompletionWindow;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    ///   A collection that stores <see cref='XmlCompletionData'/> objects.
+    /// </summary>
+    [Serializable()]
+    internal class XmlCompletionDataCollection : CollectionBase
+    {
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        public XmlCompletionDataCollection()
+        {
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlCompletionDataCollection'/> based on another <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///   A <see cref='XmlCompletionDataCollection'/> from which the contents are copied
+        /// </param>
+        public XmlCompletionDataCollection(XmlCompletionDataCollection val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlCompletionDataCollection'/> containing any array of <see cref='XmlCompletionData'/> objects.
+        /// </summary>
+        /// <param name='val'>
+        ///       A array of <see cref='XmlCompletionData'/> objects with which to intialize the collection
+        /// </param>
+        public XmlCompletionDataCollection(XmlCompletionData[] val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Represents the entry at the specified index of the <see cref='XmlCompletionData'/>.
+        /// </summary>
+        /// <param name='index'>The zero-based index of the entry to locate in the collection.</param>
+        /// <value>The entry at the specified index of the collection.</value>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='index'/> is outside the valid range of indexes for the collection.</exception>
+        public XmlCompletionData this[int index]
+        {
+            get
+            {
+                return ((XmlCompletionData)(List[index]));
+            }
+            set
+            {
+                List[index] = value;
+            }
+        }
+
+        /// <summary>
+        ///   Adds a <see cref='XmlCompletionData'/> with the specified value to the 
+        ///   <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <remarks>
+        /// If the completion data already exists in the collection it is not added.
+        /// </remarks>
+        /// <param name='val'>The <see cref='XmlCompletionData'/> to add.</param>
+        /// <returns>The index at which the new element was inserted.</returns>
+        /// <seealso cref='XmlCompletionDataCollection.AddRange'/>
+        public int Add(XmlCompletionData val)
+        {
+            int index = -1;
+            if (!Contains(val))
+            {
+                index = List.Add(val);
+            }
+            return index;
+        }
+
+        /// <summary>
+        ///   Copies the elements of an array to the end of the <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///    An array of type <see cref='XmlCompletionData'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='XmlCompletionDataCollection.Add'/>
+        public void AddRange(XmlCompletionData[] val)
+        {
+            for (int i = 0; i < val.Length; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Adds the contents of another <see cref='XmlCompletionDataCollection'/> to the end of the collection.
+        /// </summary>
+        /// <param name='val'>
+        ///    A <see cref='XmlCompletionDataCollection'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='XmlCompletionDataCollection.Add'/>
+        public void AddRange(XmlCompletionDataCollection val)
+        {
+            for (int i = 0; i < val.Count; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Gets a value indicating whether the 
+        ///    <see cref='XmlCompletionDataCollection'/> contains the specified <see cref='XmlCompletionData'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlCompletionData'/> to locate.</param>
+        /// <returns>
+        /// <see langword='true'/> if the <see cref='XmlCompletionData'/> is contained in the collection; 
+        ///   otherwise, <see langword='false'/>.
+        /// </returns>
+        /// <seealso cref='XmlCompletionDataCollection.IndexOf'/>
+        public bool Contains(XmlCompletionData val)
+        {
+            if (val.Text != null)
+            {
+                if (val.Text.Length > 0)
+                {
+                    return Contains(val.Text);
+                }
+            }
+            return false;
+        }
+
+        public bool Contains(string name)
+        {
+            bool contains = false;
+
+            foreach (XmlCompletionData data in this)
+            {
+                if (data.Text != null)
+                {
+                    if (data.Text.Length > 0)
+                    {
+                        if (data.Text == name)
+                        {
+                            contains = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return contains;
+        }
+
+        /// <summary>
+        ///   Copies the <see cref='XmlCompletionDataCollection'/> values to a one-dimensional <see cref='Array'/> instance at the 
+        ///    specified index.
+        /// </summary>
+        /// <param name='array'>The one-dimensional <see cref='Array'/> that is the destination of the values copied from <see cref='XmlCompletionDataCollection'/>.</param>
+        /// <param name='index'>The index in <paramref name='array'/> where copying begins.</param>
+        /// <exception cref='ArgumentException'>
+        ///   <para><paramref name='array'/> is multidimensional.</para>
+        ///   <para>-or-</para>
+        ///   <para>The number of elements in the <see cref='XmlCompletionDataCollection'/> is greater than
+        ///         the available space between <paramref name='arrayIndex'/> and the end of
+        ///         <paramref name='array'/>.</para>
+        /// </exception>
+        /// <exception cref='ArgumentNullException'><paramref name='array'/> is <see langword='null'/>. </exception>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='arrayIndex'/> is less than <paramref name='array'/>'s lowbound. </exception>
+        /// <seealso cref='Array'/>
+        public void CopyTo(XmlCompletionData[] array, int index)
+        {
+            List.CopyTo(array, index);
+        }
+
+        /// <summary>
+        ///   Copies the <see cref='XmlCompletionDataCollection'/> values to a one-dimensional <see cref='Array'/> instance at the 
+        ///    specified index.
+        /// </summary>
+        public void CopyTo(ICompletionData[] array, int index)
+        {
+            List.CopyTo(array, index);
+        }
+
+        /// <summary>
+        ///    Returns the index of a <see cref='XmlCompletionData'/> in 
+        ///       the <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlCompletionData'/> to locate.</param>
+        /// <returns>
+        ///   The index of the <see cref='XmlCompletionData'/> of <paramref name='val'/> in the 
+        ///   <see cref='XmlCompletionDataCollection'/>, if found; otherwise, -1.
+        /// </returns>
+        /// <seealso cref='XmlCompletionDataCollection.Contains'/>
+        public int IndexOf(XmlCompletionData val)
+        {
+            return List.IndexOf(val);
+        }
+
+        /// <summary>
+        ///   Inserts a <see cref='XmlCompletionData'/> into the <see cref='XmlCompletionDataCollection'/> at the specified index.
+        /// </summary>
+        /// <param name='index'>The zero-based index where <paramref name='val'/> should be inserted.</param>
+        /// <param name='val'>The <see cref='XmlCompletionData'/> to insert.</param>
+        /// <seealso cref='XmlCompletionDataCollection.Add'/>
+        public void Insert(int index, XmlCompletionData val)
+        {
+            List.Insert(index, val);
+        }
+
+        /// <summary>
+        /// Returns an array of <see cref="ICompletionData"/> items.
+        /// </summary>
+        /// <returns></returns>
+        public ICompletionData[] ToArray()
+        {
+            ICompletionData[] data = new ICompletionData[Count];
+            CopyTo(data, 0);
+            return data;
+        }
+
+        /// <summary>
+        ///  Returns an enumerator that can iterate through the <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        public new XmlCompletionDataEnumerator GetEnumerator()
+        {
+            return new XmlCompletionDataEnumerator(this);
+        }
+
+        /// <summary>
+        ///   Removes a specific <see cref='XmlCompletionData'/> from the <see cref='XmlCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlCompletionData'/> to remove from the <see cref='XmlCompletionDataCollection'/>.</param>
+        /// <exception cref='ArgumentException'><paramref name='val'/> is not found in the Collection.</exception>
+        public void Remove(XmlCompletionData val)
+        {
+            List.Remove(val);
+        }
+
+        /// <summary>
+        ///   Enumerator that can iterate through a XmlCompletionDataCollection.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        /// <seealso cref='XmlCompletionDataCollection'/>
+        /// <seealso cref='XmlCompletionData'/>
+        public class XmlCompletionDataEnumerator : IEnumerator
+        {
+            IEnumerator baseEnumerator;
+            IEnumerable temp;
+
+            /// <summary>
+            ///   Initializes a new instance of <see cref='XmlCompletionDataEnumerator'/>.
+            /// </summary>
+            public XmlCompletionDataEnumerator(XmlCompletionDataCollection mappings)
+            {
+                this.temp = ((IEnumerable)(mappings));
+                this.baseEnumerator = temp.GetEnumerator();
+            }
+
+            /// <summary>
+            ///   Gets the current <see cref='XmlCompletionData'/> in the <seealso cref='XmlCompletionDataCollection'/>.
+            /// </summary>
+            public XmlCompletionData Current
+            {
+                get
+                {
+                    return ((XmlCompletionData)(baseEnumerator.Current));
+                }
+            }
+
+            object IEnumerator.Current
+            {
+                get
+                {
+                    return baseEnumerator.Current;
+                }
+            }
+
+            /// <summary>
+            ///   Advances the enumerator to the next <see cref='XmlCompletionData'/> of the <see cref='XmlCompletionDataCollection'/>.
+            /// </summary>
+            public bool MoveNext()
+            {
+                return baseEnumerator.MoveNext();
+            }
+
+            /// <summary>
+            ///   Sets the enumerator to its initial position, which is before the first element in the <see cref='XmlCompletionDataCollection'/>.
+            /// </summary>
+            public void Reset()
+            {
+                baseEnumerator.Reset();
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataProvider.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataProvider.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlCompletionDataProvider.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,272 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using ICSharpCode.TextEditor;
+using ICSharpCode.TextEditor.Gui.CompletionWindow;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Provides the autocomplete (intellisense) data for an
+    /// xml document that specifies a known schema.
+    /// </summary>
+    internal class XmlCompletionDataProvider : ICompletionDataProvider
+    {
+        XmlSchemaCompletionDataCollection schemaCompletionDataItems;
+        XmlSchemaCompletionData defaultSchemaCompletionData;
+        string defaultNamespacePrefix = String.Empty;
+
+        public XmlCompletionDataProvider(XmlSchemaCompletionDataCollection schemaCompletionDataItems, XmlSchemaCompletionData defaultSchemaCompletionData, string defaultNamespacePrefix)
+        {
+            this.schemaCompletionDataItems = schemaCompletionDataItems;
+            this.defaultSchemaCompletionData = defaultSchemaCompletionData;
+            this.defaultNamespacePrefix = defaultNamespacePrefix;
+            DefaultIndex = 0;
+        }
+
+        public class XmlCompletionDataImageList
+        {
+            XmlCompletionDataImageList()
+            {
+            }
+
+            public static ImageList GetImageList()
+            {
+                ImageList imageList = new ImageList();
+
+                return imageList;
+            }
+        }
+
+        public ImageList ImageList
+        {
+            get
+            {
+                return XmlCompletionDataImageList.GetImageList();
+            }
+        }
+
+        /// <summary>
+        /// Overrides the default behaviour and allows special xml
+        /// characters such as '.' and ':' to be used as completion data.
+        /// </summary>
+        public CompletionDataProviderKeyResult ProcessKey(char key)
+        {
+            if (key == '\r' || key == '\t')
+            {
+                return CompletionDataProviderKeyResult.InsertionKey;
+            }
+            return CompletionDataProviderKeyResult.NormalKey;
+        }
+
+        public ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped)
+        {
+            this.PreSelection = null;
+            string text = String.Concat(textArea.Document.GetText(0, textArea.Caret.Offset), charTyped);
+
+            switch (charTyped)
+            {
+                case '=':
+                    // Namespace intellisense.
+                    if (XmlParser.IsNamespaceDeclaration(text, text.Length))
+                    {
+                        return schemaCompletionDataItems.GetNamespaceCompletionData(); ;
+                    }
+                    break;
+                case '<':
+                    // Child element intellisense.
+                    XmlElementPath parentPath = XmlParser.GetParentElementPath(text);
+                    if (parentPath.Elements.Count > 0)
+                    {
+                        return GetChildElementCompletionData(parentPath);
+                    }
+                    else if (defaultSchemaCompletionData != null)
+                    {
+                        return defaultSchemaCompletionData.GetElementCompletionData(defaultNamespacePrefix);
+                    }
+                    break;
+
+                case ' ':
+                    // Attribute intellisense.
+                    if (!XmlParser.IsInsideAttributeValue(text, text.Length))
+                    {
+                        XmlElementPath path = XmlParser.GetActiveElementStartPath(text, text.Length);
+                        if (path.Elements.Count > 0)
+                        {
+                            return GetAttributeCompletionData(path);
+                        }
+                    }
+                    break;
+
+                default:
+
+                    // Attribute value intellisense.
+                    if (XmlParser.IsAttributeValueChar(charTyped))
+                    {
+                        string attributeName = XmlParser.GetAttributeName(text, text.Length);
+                        if (attributeName.Length > 0)
+                        {
+                            XmlElementPath elementPath = XmlParser.GetActiveElementStartPath(text, text.Length);
+                            if (elementPath.Elements.Count > 0)
+                            {
+                                this.PreSelection = charTyped.ToString();
+                                return GetAttributeValueCompletionData(elementPath, attributeName);
+                            }
+                        }
+                    }
+                    break;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Finds the schema given the xml element path.
+        /// </summary>
+        public XmlSchemaCompletionData FindSchema(XmlElementPath path)
+        {
+            if (path.Elements.Count > 0)
+            {
+                string namespaceUri = path.Elements[0].Namespace;
+                if (namespaceUri.Length > 0)
+                {
+                    return schemaCompletionDataItems[namespaceUri];
+                }
+                else if (defaultSchemaCompletionData != null)
+                {
+
+                    // Use the default schema namespace if none
+                    // specified in a xml element path, otherwise
+                    // we will not find any attribute or element matches
+                    // later.
+                    foreach (QualifiedName name in path.Elements)
+                    {
+                        if (name.Namespace.Length == 0)
+                        {
+                            name.Namespace = defaultSchemaCompletionData.NamespaceUri;
+                        }
+                    }
+                    return defaultSchemaCompletionData;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Finds the schema given a namespace URI.
+        /// </summary>
+        public XmlSchemaCompletionData FindSchema(string namespaceUri)
+        {
+            return schemaCompletionDataItems[namespaceUri];
+        }
+
+        /// <summary>
+        /// Gets the schema completion data that was created from the specified 
+        /// schema filename.
+        /// </summary>
+        public XmlSchemaCompletionData FindSchemaFromFileName(string fileName)
+        {
+            return schemaCompletionDataItems.GetSchemaFromFileName(fileName);
+        }
+
+        ICompletionData[] GetChildElementCompletionData(XmlElementPath path)
+        {
+            ICompletionData[] completionData = null;
+
+            XmlSchemaCompletionData schema = FindSchema(path);
+            if (schema != null)
+            {
+                completionData = schema.GetChildElementCompletionData(path);
+            }
+
+            return completionData;
+        }
+
+        ICompletionData[] GetAttributeCompletionData(XmlElementPath path)
+        {
+            ICompletionData[] completionData = null;
+
+            XmlSchemaCompletionData schema = FindSchema(path);
+            if (schema != null)
+            {
+                completionData = schema.GetAttributeCompletionData(path);
+            }
+
+            return completionData;
+        }
+
+        ICompletionData[] GetAttributeValueCompletionData(XmlElementPath path, string name)
+        {
+            ICompletionData[] completionData = null;
+
+            XmlSchemaCompletionData schema = FindSchema(path);
+            if (schema != null)
+            {
+                completionData = schema.GetAttributeValueCompletionData(path, name);
+            }
+
+            return completionData;
+        }
+
+        public string PreSelection
+        {
+            get;
+            private set;
+        }
+
+        public int DefaultIndex
+        {
+            get;
+            private set;
+        }
+
+        public bool InsertSpace
+        {
+            get;
+            set;
+        }
+
+        public bool InsertAction(ICompletionData data, ICSharpCode.TextEditor.TextArea textArea, int insertionOffset, char key)
+        {
+            if (InsertSpace)
+            {
+                textArea.Document.Insert(insertionOffset++, " ");
+            }
+            textArea.Caret.Position = textArea.Document.OffsetToPosition(insertionOffset);
+
+            return data.InsertAction(textArea, key);
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlElementPath.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlElementPath.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlElementPath.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,191 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Represents the path to an xml element starting from the root of the
+    /// document.
+    /// </summary>
+    public class XmlElementPath
+    {
+        QualifiedNameCollection elements = new QualifiedNameCollection();
+
+        public XmlElementPath()
+        {
+        }
+
+        /// <summary>
+        /// Gets the elements specifying the path.
+        /// </summary>
+        /// <remarks>The order of the elements determines the path.</remarks>
+        public QualifiedNameCollection Elements
+        {
+            get { return elements; }
+        }
+
+        /// <summary>
+        /// Compacts the path so it only contains the elements that are from 
+        /// the namespace of the last element in the path. 
+        /// </summary>
+        /// <remarks>This method is used when we need to know the path for a
+        /// particular namespace and do not care about the complete path.
+        /// </remarks>
+        public void Compact()
+        {
+            if (elements.Count > 0)
+            {
+                QualifiedName lastName = Elements[Elements.Count - 1];
+                if (lastName != null)
+                {
+                    int index = FindNonMatchingParentElement(lastName.Namespace);
+                    if (index != -1)
+                    {
+                        RemoveParentElements(index);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// An xml element path is considered to be equal if 
+        /// each path item has the same name and namespace.
+        /// </summary>
+        public override bool Equals(object obj)
+        {
+            if (!(obj is XmlElementPath)) return false;
+            if (this == obj) return true;
+
+            XmlElementPath rhs = (XmlElementPath)obj;
+            if (elements.Count == rhs.elements.Count)
+            {
+
+                for (int i = 0; i < elements.Count; ++i)
+                {
+                    if (!elements[i].Equals(rhs.elements[i]))
+                    {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            return false;
+        }
+
+        public override int GetHashCode()
+        {
+            return elements.GetHashCode();
+        }
+
+
+        /// <summary>
+        /// Gets a string that represents the XmlElementPath.
+        /// </summary>
+        public override string ToString()
+        {
+            if (elements.Count > 0)
+            {
+                StringBuilder toString = new StringBuilder();
+                int lastIndex = elements.Count - 1;
+                for (int i = 0; i < elements.Count; ++i)
+                {
+                    string elementToString = GetElementToString(elements[i]);
+                    if (i == lastIndex)
+                    {
+                        toString.Append(elementToString);
+                    }
+                    else
+                    {
+                        toString.Append(elementToString);
+                        toString.Append(" > ");
+                    }
+                }
+                return toString.ToString();
+            }
+            return String.Empty;
+        }
+
+        /// <summary>
+        /// Removes elements up to and including the specified index.
+        /// </summary>
+        void RemoveParentElements(int index)
+        {
+            while (index >= 0)
+            {
+                --index;
+                elements.RemoveFirst();
+            }
+        }
+
+        /// <summary>
+        /// Finds the first parent that does belong in the specified
+        /// namespace.
+        /// </summary>
+        int FindNonMatchingParentElement(string namespaceUri)
+        {
+            int index = -1;
+
+            if (elements.Count > 1)
+            {
+                // Start the check from the the last but one item.
+                for (int i = elements.Count - 2; i >= 0; --i)
+                {
+                    QualifiedName name = elements[i];
+                    if (name.Namespace != namespaceUri)
+                    {
+                        index = i;
+                        break;
+                    }
+                }
+            }
+            return index;
+        }
+
+        /// <summary>
+        /// Returns the qualified name as a string. If the name has a 
+        /// prefix then it returns "prefix:element" otherwise it returns
+        /// just the element name.
+        /// </summary>
+        static string GetElementToString(QualifiedName name)
+        {
+            if (name.Prefix.Length > 0)
+            {
+                return name.Prefix + ":" + name.Name;
+            }
+            return name.Name;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlParser.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlParser.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlParser.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,942 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Utility class that contains xml parsing routines used to determine
+    /// the currently selected element so we can provide intellisense.
+    /// </summary>
+    /// <remarks>
+    /// All of the routines return <see cref="XmlElementPath"/> objects
+    /// since we are interested in the complete path or tree to the
+    /// currently active element.
+    /// </remarks>
+    internal class XmlParser
+    {
+        /// <summary>
+        /// Helper class.  Holds the namespace URI and the prefix currently
+        /// in use for this namespace.
+        /// </summary>
+        class NamespaceURI
+        {
+            string namespaceURI = String.Empty;
+            string prefix = String.Empty;
+
+            public NamespaceURI()
+            {
+            }
+
+            public NamespaceURI(string namespaceURI, string prefix)
+            {
+                this.namespaceURI = namespaceURI;
+                this.prefix = prefix;
+            }
+
+            public string Namespace
+            {
+                get { return namespaceURI; }
+                set { namespaceURI = value; }
+            }
+
+            public string Prefix
+            {
+                get { return prefix; }
+                set
+                {
+                    prefix = value;
+                    if (prefix == null)
+                    {
+                        prefix = String.Empty;
+                    }
+                }
+            }
+
+            public override string ToString()
+            {
+                if (!String.IsNullOrEmpty(prefix))
+                {
+                    return prefix + ":" + namespaceURI;
+                }
+                return namespaceURI;
+            }
+        }
+
+        static readonly char[] whitespaceCharacters = new char[] { ' ', '\n', '\t', '\r' };
+
+        XmlParser()
+        {
+        }
+
+        /// <summary>
+        /// Gets path of the xml element start tag that the specified
+        /// <paramref name="index"/> is currently inside.
+        /// </summary>
+        /// <remarks>If the index outside the start tag then an empty path
+        /// is returned.</remarks>
+        public static XmlElementPath GetActiveElementStartPath(string xml, int index)
+        {
+            QualifiedNameCollection namespaces = new QualifiedNameCollection();
+            return GetActiveElementStartPath(xml, index, namespaces);
+        }
+
+        /// <summary>
+        /// Gets path of the xml element start tag that the specified
+        /// <paramref name="index"/> is currently located. This is different to the
+        /// GetActiveElementStartPath method since the index can be inside the element
+        /// name.
+        /// </summary>
+        /// <remarks>If the index outside the start tag then an empty path
+        /// is returned.</remarks>
+        public static XmlElementPath GetActiveElementStartPathAtIndex(string xml, int index)
+        {
+            QualifiedNameCollection namespaces = new QualifiedNameCollection();
+            return GetActiveElementStartPathAtIndex(xml, index, namespaces);
+        }
+
+        /// <summary>
+        /// Gets the parent element path based on the index position.
+        /// </summary>
+        public static XmlElementPath GetParentElementPath(string xml)
+        {
+            QualifiedNameCollection namespaces = new QualifiedNameCollection();
+            XmlElementPath path = GetFullParentElementPath(xml, namespaces);
+            path.Compact();
+            return path;
+        }
+
+        /// <summary>
+        /// Checks whether the attribute at the end of the string is a
+        /// namespace declaration.
+        /// </summary>
+        public static bool IsNamespaceDeclaration(string xml, int index)
+        {
+            if (String.IsNullOrEmpty(xml))
+            {
+                return false;
+            }
+
+            index = GetCorrectedIndex(xml.Length, index);
+
+            // Move back one character if the last character is an '='
+            if (xml[index] == '=')
+            {
+                xml = xml.Substring(0, xml.Length - 1);
+                --index;
+            }
+
+            // From the end of the string work backwards until we have
+            // picked out the last attribute and reached some whitespace.
+            StringBuilder reversedAttributeName = new StringBuilder();
+
+            bool ignoreWhitespace = true;
+            int currentIndex = index;
+            for (int i = 0; i < index; ++i)
+            {
+
+                char currentChar = xml[currentIndex];
+
+                if (Char.IsWhiteSpace(currentChar))
+                {
+                    if (ignoreWhitespace == false)
+                    {
+                        // Reached the start of the attribute name.
+                        break;
+                    }
+                }
+                else if (Char.IsLetterOrDigit(currentChar) || (currentChar == ':'))
+                {
+                    ignoreWhitespace = false;
+                    reversedAttributeName.Append(currentChar);
+                }
+                else
+                {
+                    // Invalid string.
+                    break;
+                }
+
+                --currentIndex;
+            }
+
+            // Did we get a namespace?
+
+            bool isNamespace = false;
+
+            if ((reversedAttributeName.ToString() == "snlmx") || (reversedAttributeName.ToString().EndsWith(":snlmx")))
+            {
+                isNamespace = true;
+            }
+
+            return isNamespace;
+        }
+
+        /// <summary>
+        /// Gets the attribute name and any prefix. The namespace
+        /// is not determined.
+        /// </summary>
+        /// <returns><see langword="null"/> if no attribute name can
+        /// be found.</returns>
+        public static QualifiedName GetQualifiedAttributeName(string xml, int index)
+        {
+            string name = GetAttributeName(xml, index);
+            return GetQualifiedName(name);
+        }
+
+        /// <summary>
+        /// Gets the name of the attribute inside but before the specified
+        /// index.
+        /// </summary>
+        public static string GetAttributeName(string xml, int index)
+        {
+            if (String.IsNullOrEmpty(xml))
+            {
+                return String.Empty;
+            }
+
+            index = GetCorrectedIndex(xml.Length, index);
+            return GetAttributeName(xml, index, true, true, true);
+        }
+
+        /// <summary>
+        /// Gets the name of the attribute and its prefix at the specified index. The index
+        /// can be anywhere inside the attribute name or in the attribute value.
+        /// The namespace for the element containing the attribute will also be determined
+        /// if the includeNamespace flag is set to true.
+        /// </summary>
+        public static QualifiedName GetQualifiedAttributeNameAtIndex(string xml, int index, bool includeNamespace)
+        {
+            string name = GetAttributeNameAtIndex(xml, index);
+            QualifiedName qualifiedName = GetQualifiedName(name);
+            if (qualifiedName != null && String.IsNullOrEmpty(qualifiedName.Namespace) && includeNamespace)
+            {
+                QualifiedNameCollection namespaces = new QualifiedNameCollection();
+                XmlElementPath path = GetActiveElementStartPathAtIndex(xml, index, namespaces);
+                qualifiedName.Namespace = GetNamespaceForPrefix(namespaces, path.Elements.LastPrefix);
+            }
+            return qualifiedName;
+        }
+
+        /// <summary>
+        /// Gets the name of the attribute and its prefix at the specified index. The index
+        /// can be anywhere inside the attribute name or in the attribute value.
+        /// </summary>
+        public static QualifiedName GetQualifiedAttributeNameAtIndex(string xml, int index)
+        {
+            return GetQualifiedAttributeNameAtIndex(xml, index, false);
+        }
+
+        /// <summary>
+        /// Gets the name of the attribute at the specified index. The index
+        /// can be anywhere inside the attribute name or in the attribute value.
+        /// </summary>
+        public static string GetAttributeNameAtIndex(string xml, int index)
+        {
+            if (String.IsNullOrEmpty(xml))
+            {
+                return String.Empty;
+            }
+
+            index = GetCorrectedIndex(xml.Length, index);
+
+            bool ignoreWhitespace = true;
+            bool ignoreEqualsSign = false;
+            bool ignoreQuote = false;
+
+            if (IsInsideAttributeValue(xml, index))
+            {
+                // Find attribute name start.
+                int elementStartIndex = GetActiveElementStartIndex(xml, index);
+                if (elementStartIndex == -1)
+                {
+                    return String.Empty;
+                }
+
+                // Find equals sign.
+                for (int i = index; i > elementStartIndex; --i)
+                {
+                    char ch = xml[i];
+                    if (ch == '=')
+                    {
+                        index = i;
+                        ignoreEqualsSign = true;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                // Find end of attribute name.
+                for (; index < xml.Length; ++index)
+                {
+                    char ch = xml[index];
+                    if (!IsXmlNameChar(ch))
+                    {
+                        if (ch == '\'' || ch == '\"')
+                        {
+                            ignoreQuote = true;
+                            ignoreEqualsSign = true;
+                        }
+                        break;
+                    }
+                }
+                --index;
+            }
+
+            return GetAttributeName(xml, index, ignoreWhitespace, ignoreQuote, ignoreEqualsSign);
+        }
+
+        /// <summary>
+        /// Checks for valid xml attribute value character
+        /// </summary>
+        public static bool IsAttributeValueChar(char ch)
+        {
+            if ((ch == '<') ||
+                (ch == '>'))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Checks for valid xml element or attribute name character.
+        /// </summary>
+        public static bool IsXmlNameChar(char ch)
+        {
+            if (Char.IsLetterOrDigit(ch) ||
+                (ch == ':') ||
+                (ch == '/') ||
+                (ch == '_') ||
+                (ch == '.') ||
+                (ch == '-'))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Determines whether the specified index is inside an attribute value.
+        /// </summary>
+        public static bool IsInsideAttributeValue(string xml, int index)
+        {
+            if (String.IsNullOrEmpty(xml))
+            {
+                return false;
+            }
+
+            if (index > xml.Length)
+            {
+                index = xml.Length;
+            }
+
+            int elementStartIndex = GetActiveElementStartIndex(xml, index);
+            if (elementStartIndex == -1)
+            {
+                return false;
+            }
+
+            // Count the number of double quotes and single quotes that exist
+            // before the first equals sign encountered going backwards to
+            // the start of the active element.
+            bool foundEqualsSign = false;
+            int doubleQuotesCount = 0;
+            int singleQuotesCount = 0;
+            char lastQuoteChar = ' ';
+            for (int i = index - 1; i > elementStartIndex; --i)
+            {
+                char ch = xml[i];
+                if (ch == '=')
+                {
+                    foundEqualsSign = true;
+                    break;
+                }
+                else if (ch == '\"')
+                {
+                    lastQuoteChar = ch;
+                    ++doubleQuotesCount;
+                }
+                else if (ch == '\'')
+                {
+                    lastQuoteChar = ch;
+                    ++singleQuotesCount;
+                }
+            }
+
+            bool isInside = false;
+
+            if (foundEqualsSign)
+            {
+                // Odd number of quotes?
+                if ((lastQuoteChar == '\"') && ((doubleQuotesCount % 2) > 0))
+                {
+                    isInside = true;
+                }
+                else if ((lastQuoteChar == '\'') && ((singleQuotesCount % 2) > 0))
+                {
+                    isInside = true;
+                }
+            }
+
+            return isInside;
+        }
+
+        /// <summary>
+        /// Gets the attribute value at the specified index.
+        /// </summary>
+        /// <returns>An empty string if no attribute value can be found.</returns>
+        public static string GetAttributeValueAtIndex(string xml, int index)
+        {
+            if (!IsInsideAttributeValue(xml, index))
+            {
+                return String.Empty;
+            }
+
+            index = GetCorrectedIndex(xml.Length, index);
+
+            int elementStartIndex = GetActiveElementStartIndex(xml, index);
+            if (elementStartIndex == -1)
+            {
+                return String.Empty;
+            }
+
+            // Find equals sign.
+            int equalsSignIndex = -1;
+            for (int i = index; i > elementStartIndex; --i)
+            {
+                char ch = xml[i];
+                if (ch == '=')
+                {
+                    equalsSignIndex = i;
+                    break;
+                }
+            }
+
+            if (equalsSignIndex == -1)
+            {
+                return String.Empty;
+            }
+
+            // Find attribute value.
+            char quoteChar = ' ';
+            bool foundQuoteChar = false;
+            StringBuilder attributeValue = new StringBuilder();
+            for (int i = equalsSignIndex; i < xml.Length; ++i)
+            {
+                char ch = xml[i];
+                if (!foundQuoteChar)
+                {
+                    if (ch == '\"' || ch == '\'')
+                    {
+                        quoteChar = ch;
+                        foundQuoteChar = true;
+                    }
+                }
+                else
+                {
+                    if (ch == quoteChar)
+                    {
+                        // End of attribute value.
+                        return attributeValue.ToString();
+                    }
+                    else if (IsAttributeValueChar(ch) || (ch == '\"' || ch == '\''))
+                    {
+                        attributeValue.Append(ch);
+                    }
+                    else
+                    {
+                        // Invalid character found.
+                        return String.Empty;
+                    }
+                }
+            }
+
+            return String.Empty;
+        }
+
+        /// <summary>
+        /// Gets the text of the xml element start tag that the index is
+        /// currently inside.
+        /// </summary>
+        /// <returns>
+        /// Returns the text up to and including the start tag < character.
+        /// </returns>
+        static string GetActiveElementStartText(string xml, int index)
+        {
+            int elementStartIndex = GetActiveElementStartIndex(xml, index);
+            if (elementStartIndex >= 0)
+            {
+                if (elementStartIndex < index)
+                {
+                    int elementEndIndex = GetActiveElementEndIndex(xml, index);
+                    if (elementEndIndex >= index)
+                    {
+                        return xml.Substring(elementStartIndex, elementEndIndex - elementStartIndex);
+                    }
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Locates the index of the start tag < character.
+        /// </summary>
+        /// <returns>
+        /// Returns the index of the start tag character; otherwise
+        /// -1 if no start tag character is found or a end tag
+        /// > character is found first.
+        /// </returns>
+        static int GetActiveElementStartIndex(string xml, int index)
+        {
+            int elementStartIndex = -1;
+
+            int currentIndex = index - 1;
+
+            for (int i = 0; i < index; ++i)
+            {
+
+                char currentChar = xml[currentIndex];
+                if (currentChar == '<')
+                {
+                    elementStartIndex = currentIndex;
+                    break;
+                }
+                else if (currentChar == '>')
+                {
+                    break;
+                }
+
+                --currentIndex;
+            }
+
+            return elementStartIndex;
+        }
+
+        /// <summary>
+        /// Locates the index of the end tag character.
+        /// </summary>
+        /// <returns>
+        /// Returns the index of the end tag character; otherwise
+        /// -1 if no end tag character is found or a start tag
+        /// character is found first.
+        /// </returns>
+        static int GetActiveElementEndIndex(string xml, int index)
+        {
+            int elementEndIndex = index;
+
+            for (int i = index; i < xml.Length; ++i)
+            {
+
+                char currentChar = xml[i];
+                if (currentChar == '>')
+                {
+                    elementEndIndex = i;
+                    break;
+                }
+                else if (currentChar == '<')
+                {
+                    elementEndIndex = -1;
+                    break;
+                }
+            }
+
+            return elementEndIndex;
+        }
+
+        /// <summary>
+        /// Gets the element name from the element start tag string.
+        /// </summary>
+        /// <param name="xml">This string must start at the
+        /// element we are interested in.</param>
+        static QualifiedName GetElementName(string xml)
+        {
+            string name = String.Empty;
+
+            // Find the end of the element name.
+            xml = xml.Replace("\r\n", " ");
+            int index = xml.IndexOf(' ');
+            if (index > 0)
+            {
+                name = xml.Substring(1, index - 1);
+            }
+            else
+            {
+                name = xml.Substring(1);
+            }
+
+            return GetQualifiedName(name);
+        }
+
+        /// <summary>
+        /// Gets the element namespace from the element start tag
+        /// string.
+        /// </summary>
+        /// <param name="xml">This string must start at the
+        /// element we are interested in.</param>
+        static NamespaceURI GetElementNamespace(string xml)
+        {
+            NamespaceURI namespaceURI = new NamespaceURI();
+
+            Match match = Regex.Match(xml, ".*?(xmlns\\s*?|xmlns:.*?)=\\s*?['\\\"](.*?)['\\\"]");
+            if (match.Success)
+            {
+                namespaceURI.Namespace = match.Groups[2].Value;
+
+                string xmlns = match.Groups[1].Value.Trim();
+                int prefixIndex = xmlns.IndexOf(':');
+                if (prefixIndex > 0)
+                {
+                    namespaceURI.Prefix = xmlns.Substring(prefixIndex + 1);
+                }
+            }
+
+            return namespaceURI;
+        }
+
+        static string ReverseString(string text)
+        {
+            StringBuilder reversedString = new StringBuilder(text);
+
+            int index = text.Length;
+            foreach (char ch in text)
+            {
+                --index;
+                reversedString[index] = ch;
+            }
+
+            return reversedString.ToString();
+        }
+
+        /// <summary>
+        /// Ensures that the index is on the last character if it is
+        /// too large.
+        /// </summary>
+        /// <param name="length">The length of the string.</param>
+        /// <param name="index">The current index.</param>
+        /// <returns>The index unchanged if the index is smaller than the
+        /// length of the string; otherwise it returns length - 1.</returns>
+        static int GetCorrectedIndex(int length, int index)
+        {
+            if (index >= length)
+            {
+                index = length - 1;
+            }
+            return index;
+        }
+
+        /// <summary>
+        /// Gets the active element path given the element text.
+        /// </summary>
+        static XmlElementPath GetActiveElementStartPath(string xml, int index, string elementText, QualifiedNameCollection namespaces)
+        {
+            QualifiedName elementName = GetElementName(elementText);
+            if (elementName == null)
+            {
+                return new XmlElementPath();
+            }
+
+            NamespaceURI elementNamespace = GetElementNamespace(elementText);
+
+            XmlElementPath path = GetFullParentElementPath(xml.Substring(0, index), namespaces);
+
+            // Try to get a namespace for the active element's prefix.
+            if (elementName.Prefix.Length > 0 && elementNamespace.Namespace.Length == 0)
+            {
+                elementName.Namespace = GetNamespaceForPrefix(namespaces, elementName.Prefix);
+                elementNamespace.Namespace = elementName.Namespace;
+                elementNamespace.Prefix = elementName.Prefix;
+            }
+
+            if (elementNamespace.Namespace.Length == 0)
+            {
+                if (path.Elements.Count > 0)
+                {
+                    QualifiedName parentName = path.Elements[path.Elements.Count - 1];
+                    elementNamespace.Namespace = parentName.Namespace;
+                    elementNamespace.Prefix = parentName.Prefix;
+                }
+            }
+            path.Elements.Add(new QualifiedName(elementName.Name, elementNamespace.Namespace, elementNamespace.Prefix));
+            path.Compact();
+            return path;
+        }
+
+        static string GetAttributeName(string xml, int index, bool ignoreWhitespace, bool ignoreQuote, bool ignoreEqualsSign)
+        {
+            string name = String.Empty;
+
+            // From the end of the string work backwards until we have
+            // picked out the attribute name.
+            StringBuilder reversedAttributeName = new StringBuilder();
+
+            int currentIndex = index;
+            bool invalidString = true;
+
+            for (int i = 0; i <= index; ++i)
+            {
+
+                char currentChar = xml[currentIndex];
+
+                if (IsXmlNameChar(currentChar))
+                {
+                    if (!ignoreEqualsSign)
+                    {
+                        ignoreWhitespace = false;
+                        reversedAttributeName.Append(currentChar);
+                    }
+                }
+                else if (Char.IsWhiteSpace(currentChar))
+                {
+                    if (ignoreWhitespace == false)
+                    {
+                        // Reached the start of the attribute name.
+                        invalidString = false;
+                        break;
+                    }
+                }
+                else if ((currentChar == '\'') || (currentChar == '\"'))
+                {
+                    if (ignoreQuote)
+                    {
+                        ignoreQuote = false;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                else if (currentChar == '=')
+                {
+                    if (ignoreEqualsSign)
+                    {
+                        ignoreEqualsSign = false;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                else if (IsAttributeValueChar(currentChar))
+                {
+                    if (!ignoreQuote)
+                    {
+                        break;
+                    }
+                }
+                else
+                {
+                    break;
+                }
+
+                --currentIndex;
+            }
+
+            if (!invalidString)
+            {
+                name = ReverseString(reversedAttributeName.ToString());
+            }
+
+            return name;
+        }
+
+        /// <summary>
+        /// Gets the element name at the specified index.
+        /// </summary>
+        static string GetElementNameAtIndex(string xml, int index)
+        {
+            int elementStartIndex = GetActiveElementStartIndex(xml, index);
+            if (elementStartIndex >= 0 && elementStartIndex < index)
+            {
+                int elementEndIndex = GetActiveElementEndIndex(xml, index);
+                if (elementEndIndex == -1)
+                {
+                    elementEndIndex = xml.IndexOfAny(whitespaceCharacters, elementStartIndex);
+                }
+                if (elementEndIndex >= elementStartIndex)
+                {
+                    return xml.Substring(elementStartIndex, elementEndIndex - elementStartIndex);
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Returns a name and its prefix.
+        /// </summary>
+        static QualifiedName GetQualifiedName(string name)
+        {
+            if (name.Length == 0)
+            {
+                return null;
+            }
+
+            QualifiedName qualifiedName = new QualifiedName();
+            int prefixIndex = name.IndexOf(':');
+            if (prefixIndex > 0)
+            {
+                qualifiedName.Prefix = name.Substring(0, prefixIndex);
+                qualifiedName.Name = name.Substring(prefixIndex + 1);
+            }
+            else
+            {
+                qualifiedName.Name = name;
+            }
+            return qualifiedName;
+        }
+
+        /// <summary>
+        /// Gets the parent element path based on the index position. This
+        /// method does not compact the path so it will include all elements
+        /// including those in another namespace in the path.
+        /// </summary>
+        static XmlElementPath GetFullParentElementPath(string xml, QualifiedNameCollection namespaces)
+        {
+            XmlElementPath path = new XmlElementPath();
+            IDictionary<string, string> namespacesInScope = null;
+            using (StringReader reader = new StringReader(xml))
+            {
+                using (XmlTextReader xmlReader = new XmlTextReader(reader))
+                {
+                    try
+                    {
+                        xmlReader.XmlResolver = null; // prevent XmlTextReader from loading external DTDs
+                        while (xmlReader.Read())
+                        {
+                            switch (xmlReader.NodeType)
+                            {
+                                case XmlNodeType.Element:
+                                    if (!xmlReader.IsEmptyElement)
+                                    {
+                                        QualifiedName elementName = new QualifiedName(xmlReader.LocalName, xmlReader.NamespaceURI, xmlReader.Prefix);
+                                        path.Elements.Add(elementName);
+                                    }
+                                    break;
+                                case XmlNodeType.EndElement:
+                                    path.Elements.RemoveLast();
+                                    break;
+                            }
+                        }
+                    }
+                    catch (XmlException)
+                    {
+                        namespacesInScope = xmlReader.GetNamespacesInScope(XmlNamespaceScope.All);
+                    }
+                }
+            }
+
+            // Add namespaces in scope for the last element read.
+            if (namespacesInScope != null)
+            {
+                foreach (KeyValuePair<string, string> ns in namespacesInScope)
+                {
+                    namespaces.Add(new QualifiedName(String.Empty, ns.Value, ns.Key));
+                }
+            }
+
+            return path;
+        }
+
+        /// <summary>
+        /// Finds the namespace for the specified prefix.
+        /// </summary>
+        static string GetNamespaceForPrefix(QualifiedNameCollection namespaces, string prefix)
+        {
+            foreach (QualifiedName name in namespaces)
+            {
+                if (name.Prefix == prefix)
+                {
+                    return name.Namespace;
+                }
+            }
+            return String.Empty;
+        }
+
+        /// <summary>
+        /// Gets path of the xml element start tag that the specified
+        /// <paramref name="index"/> is currently inside.
+        /// </summary>
+        /// <remarks>If the index outside the start tag then an empty path
+        /// is returned.</remarks>
+        /// <param name="namespaces">Returns the namespaces that are
+        /// exist in the xml.</param>
+        static XmlElementPath GetActiveElementStartPath(string xml, int index, QualifiedNameCollection namespaces)
+        {
+            XmlElementPath path = new XmlElementPath();
+            string elementText = GetActiveElementStartText(xml, index);
+            if (elementText != null)
+            {
+                path = GetActiveElementStartPath(xml, index, elementText, namespaces);
+            }
+            return path;
+        }
+
+        /// <summary>
+        /// Gets path of the xml element start tag that the specified
+        /// <paramref name="index"/> is currently located. This is different to the
+        /// GetActiveElementStartPath method since the index can be inside the element
+        /// name.
+        /// </summary>
+        /// <remarks>If the index outside the start tag then an empty path
+        /// is returned.</remarks>
+        static XmlElementPath GetActiveElementStartPathAtIndex(string xml, int index, QualifiedNameCollection namespaces)
+        {
+            // Find first non xml element name character to the right of the index.
+            index = GetCorrectedIndex(xml.Length, index);
+            if (index < 0) // can happen when xml.Length==0
+                return new XmlElementPath();
+            int currentIndex = index;
+            for (; currentIndex < xml.Length; ++currentIndex)
+            {
+                char ch = xml[currentIndex];
+                if (!IsXmlNameChar(ch))
+                {
+                    break;
+                }
+            }
+
+            string elementText = GetElementNameAtIndex(xml, currentIndex);
+            if (elementText != null)
+            {
+                return GetActiveElementStartPath(xml, currentIndex, elementText, namespaces);
+            }
+            return new XmlElementPath();
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaAssociation.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaAssociation.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaAssociation.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,195 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Represents an association between an xml schema and a file extension.
+    /// </summary>
+    public class XmlSchemaAssociation //: IXmlConvertable
+    {
+        string namespaceUri = String.Empty;
+        string extension = String.Empty;
+        string namespacePrefix = String.Empty;
+
+        public XmlSchemaAssociation(string extension)
+            : this(extension, String.Empty, String.Empty)
+        {
+        }
+
+        public XmlSchemaAssociation(string extension, string namespaceUri)
+            : this(extension, namespaceUri, String.Empty)
+        {
+        }
+
+        public XmlSchemaAssociation(string extension, string namespaceUri, string namespacePrefix)
+        {
+            this.extension = extension;
+            this.namespaceUri = namespaceUri;
+            this.namespacePrefix = namespacePrefix;
+        }
+
+        public string NamespaceUri
+        {
+            get
+            {
+                return namespaceUri;
+            }
+
+            set
+            {
+                namespaceUri = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the file extension (e.g. '.xml').
+        /// </summary>
+        public string Extension
+        {
+            get
+            {
+                return extension;
+            }
+
+            set
+            {
+                extension = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the default namespace prefix that will be added
+        /// to the xml elements.
+        /// </summary>
+        public string NamespacePrefix
+        {
+            get
+            {
+                return namespacePrefix;
+            }
+
+            set
+            {
+                namespacePrefix = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the default schema association for the file extension. 
+        /// </summary>
+        /// <remarks>
+        /// These defaults are hard coded.
+        /// </remarks>
+        public static XmlSchemaAssociation GetDefaultAssociation(string extension)
+        {
+            XmlSchemaAssociation association = null;
+
+            switch (extension.ToLowerInvariant())
+            {
+                case ".wxs":
+                    association = new XmlSchemaAssociation(extension, @"http://schemas.microsoft.com/wix/2003/01/wi");
+                    break;
+                case ".config":
+                    association = new XmlSchemaAssociation(extension, @"urn:app-config");
+                    break;
+                case ".build":
+                    association = new XmlSchemaAssociation(extension, @"http://nant.sf.net/release/0.85/nant.xsd");
+                    break;
+                case ".addin":
+                    association = new XmlSchemaAssociation(extension, @"http://www.icsharpcode.net/2005/addin");
+                    break;
+                case ".xsl":
+                case ".xslt":
+                    association = new XmlSchemaAssociation(extension, @"http://www.w3.org/1999/XSL/Transform", "xsl");
+                    break;
+                case ".xsd":
+                    association = new XmlSchemaAssociation(extension, @"http://www.w3.org/2001/XMLSchema", "xs");
+                    break;
+                case ".manifest":
+                    association = new XmlSchemaAssociation(extension, @"urn:schemas-microsoft-com:asm.v1");
+                    break;
+                case ".xaml":
+                    association = new XmlSchemaAssociation(extension, @"http://schemas.microsoft.com/winfx/avalon/2005");
+                    break;
+                default:
+                    association = new XmlSchemaAssociation(extension);
+                    break;
+            }
+            return association;
+        }
+
+        /// <summary>
+        /// Two schema associations are considered equal if their file extension,
+        /// prefix and namespaceUri are the same.
+        /// </summary>
+        public override bool Equals(object obj)
+        {
+            bool equals = false;
+
+            XmlSchemaAssociation rhs = obj as XmlSchemaAssociation;
+            if (rhs != null)
+            {
+                if ((this.namespacePrefix == rhs.namespacePrefix) &&
+                    (this.extension == rhs.extension) &&
+                    (this.namespaceUri == rhs.namespaceUri))
+                {
+                    equals = true;
+                }
+            }
+
+            return equals;
+        }
+
+        public override int GetHashCode()
+        {
+            return (namespaceUri != null ? namespaceUri.GetHashCode() : 0) ^ (extension != null ? extension.GetHashCode() : 0) ^ (namespacePrefix != null ? namespacePrefix.GetHashCode() : 0);
+        }
+
+        /// <summary>
+        /// Creates an XmlSchemaAssociation from the saved xml.
+        /// </summary>
+        public static XmlSchemaAssociation ConvertFromString(string text)
+        {
+            string[] parts = text.Split(new char[] { '|' }, 3);
+            return new XmlSchemaAssociation(parts[0], parts[1], parts[2]);
+        }
+
+        public string ConvertToString()
+        {
+            return extension + "|" + namespaceUri + "|" + namespacePrefix;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionData.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionData.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionData.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,1607 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using ICSharpCode.TextEditor.Gui.CompletionWindow;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
+using System.Xml.Schema;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Holds the completion (intellisense) data for an xml schema.
+    /// </summary>
+    /// <remarks>
+    /// The XmlSchema class throws an exception if we attempt to load 
+    /// the xhtml1-strict.xsd schema.  It does not like the fact that
+    /// this schema redefines the xml namespace, even though this is
+    /// allowed by the w3.org specification.
+    /// </remarks>
+    public class XmlSchemaCompletionData
+    {
+        string namespaceUri = String.Empty;
+        XmlSchema schema;
+        string fileName = String.Empty;
+        bool readOnly = false;
+
+        /// <summary>
+        /// Stores attributes that have been prohibited whilst the code
+        /// generates the attribute completion data.
+        /// </summary>
+        XmlSchemaObjectCollection prohibitedAttributes = new XmlSchemaObjectCollection();
+
+        public XmlSchemaCompletionData()
+        {
+        }
+
+        /// <summary>
+        /// Creates completion data from the schema passed in 
+        /// via the reader object.
+        /// </summary>
+        public XmlSchemaCompletionData(TextReader reader)
+        {
+            ReadSchema(String.Empty, reader);
+        }
+
+        /// <summary>
+        /// Creates completion data from the schema passed in 
+        /// via the reader object.
+        /// </summary>
+        public XmlSchemaCompletionData(XmlTextReader reader)
+        {
+            reader.XmlResolver = null;
+            ReadSchema(reader);
+        }
+
+        /// <summary>
+        /// Creates the completion data from the specified schema file.
+        /// </summary>
+        public XmlSchemaCompletionData(string fileName)
+            : this(String.Empty, fileName)
+        {
+        }
+
+        /// <summary>
+        /// Creates the completion data from the specified schema file and uses
+        /// the specified baseUri to resolve any referenced schemas.
+        /// </summary>
+        public XmlSchemaCompletionData(string baseUri, string fileName)
+        {
+            StreamReader reader = new StreamReader(fileName, true);
+            ReadSchema(baseUri, reader);
+            this.fileName = fileName;
+        }
+
+        /// <summary>
+        /// Gets the schema.
+        /// </summary>
+        public XmlSchema Schema
+        {
+            get
+            {
+                return schema;
+            }
+        }
+
+        /// <summary>
+        /// Read only schemas are those that are installed with 
+        /// SharpDevelop.
+        /// </summary>
+        public bool ReadOnly
+        {
+            get
+            {
+                return readOnly;
+            }
+
+            set
+            {
+                readOnly = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the schema's file name.
+        /// </summary>
+        public string FileName
+        {
+            get
+            {
+                return fileName;
+            }
+            set
+            {
+                fileName = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets the namespace URI for the schema.
+        /// </summary>
+        public string NamespaceUri
+        {
+            get
+            {
+                return namespaceUri;
+            }
+        }
+
+        /// <summary>
+        /// Converts the filename into a valid Uri.
+        /// </summary>
+        public static string GetUri(string fileName)
+        {
+            string uri = String.Empty;
+
+            if (fileName != null)
+            {
+                if (fileName.Length > 0)
+                {
+                    uri = String.Concat("file:///", fileName.Replace('\\', '/'));
+                }
+            }
+
+            return uri;
+        }
+
+        /// <summary>
+        /// Gets the possible root elements for an xml document using this schema.
+        /// </summary>
+        public ICompletionData[] GetElementCompletionData()
+        {
+            return GetElementCompletionData(String.Empty);
+        }
+
+        /// <summary>
+        /// Gets the possible root elements for an xml document using this schema.
+        /// </summary>
+        public ICompletionData[] GetElementCompletionData(string namespacePrefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            foreach (XmlSchemaElement element in schema.Elements.Values)
+            {
+                if (element.Name != null)
+                {
+                    AddElement(data, element.Name, namespacePrefix, element.Annotation);
+                }
+                else
+                {
+                    // Do not add reference element.
+                }
+            }
+
+            return data.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the attribute completion data for the xml element that exists
+        /// at the end of the specified path.
+        /// </summary>
+        public ICompletionData[] GetAttributeCompletionData(XmlElementPath path)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            // Locate matching element.
+            XmlSchemaElement element = FindElement(path);
+
+            // Get completion data.
+            if (element != null)
+            {
+                prohibitedAttributes.Clear();
+                data = GetAttributeCompletionData(element);
+            }
+
+            return data.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the child element completion data for the xml element that exists
+        /// at the end of the specified path.
+        /// </summary>
+        public ICompletionData[] GetChildElementCompletionData(XmlElementPath path)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            // Locate matching element.
+            XmlSchemaElement element = FindElement(path);
+
+            // Get completion data.
+            if (element != null)
+            {
+                data = GetChildElementCompletionData(element, path.Elements.LastPrefix);
+            }
+
+            return data.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the autocomplete data for the specified attribute value.
+        /// </summary>
+        public ICompletionData[] GetAttributeValueCompletionData(XmlElementPath path, string name)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            // Locate matching element.
+            XmlSchemaElement element = FindElement(path);
+
+            // Get completion data.
+            if (element != null)
+            {
+                data = GetAttributeValueCompletionData(element, name);
+            }
+
+            return data.ToArray();
+        }
+
+        /// <summary>
+        /// Finds the element that exists at the specified path.
+        /// </summary>
+        /// <remarks>This method is not used when generating completion data,
+        /// but is a useful method when locating an element so we can jump
+        /// to its schema definition.</remarks>
+        /// <returns><see langword="null"/> if no element can be found.</returns>
+        public XmlSchemaElement FindElement(XmlElementPath path)
+        {
+            XmlSchemaElement element = null;
+            for (int i = 0; i < path.Elements.Count; ++i)
+            {
+                QualifiedName name = path.Elements[i];
+                if (i == 0)
+                {
+                    // Look for root element.
+                    element = FindElement(name);
+                    if (element == null)
+                    {
+                        break;
+                    }
+                }
+                else
+                {
+                    element = FindChildElement(element, name);
+                    if (element == null)
+                    {
+                        break;
+                    }
+                }
+            }
+            return element;
+        }
+
+        /// <summary>
+        /// Finds an element in the schema.
+        /// </summary>
+        /// <remarks>
+        /// Only looks at the elements that are defined in the 
+        /// root of the schema so it will not find any elements
+        /// that are defined inside any complex types.
+        /// </remarks>
+        public XmlSchemaElement FindElement(QualifiedName name)
+        {
+            foreach (XmlSchemaElement element in schema.Elements.Values)
+            {
+                if (name.Equals(element.QualifiedName))
+                {
+                    return element;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Finds the complex type with the specified name.
+        /// </summary>
+        public XmlSchemaComplexType FindComplexType(QualifiedName name)
+        {
+            XmlQualifiedName qualifiedName = new XmlQualifiedName(name.Name, name.Namespace);
+            return FindNamedType(schema, qualifiedName);
+        }
+
+        /// <summary>
+        /// Finds the specified attribute name given the element.
+        /// </summary>
+        /// <remarks>This method is not used when generating completion data,
+        /// but is a useful method when locating an attribute so we can jump
+        /// to its schema definition.</remarks>
+        /// <returns><see langword="null"/> if no attribute can be found.</returns>
+        public XmlSchemaAttribute FindAttribute(XmlSchemaElement element, string name)
+        {
+            XmlSchemaAttribute attribute = null;
+            XmlSchemaComplexType complexType = GetElementAsComplexType(element);
+            if (complexType != null)
+            {
+                attribute = FindAttribute(complexType, name);
+            }
+            return attribute;
+        }
+
+        /// <summary>
+        /// Finds the attribute group with the specified name.
+        /// </summary>
+        public XmlSchemaAttributeGroup FindAttributeGroup(string name)
+        {
+            return FindAttributeGroup(schema, name);
+        }
+
+        /// <summary>
+        /// Finds the simple type with the specified name.
+        /// </summary>
+        public XmlSchemaSimpleType FindSimpleType(string name)
+        {
+            XmlQualifiedName qualifiedName = new XmlQualifiedName(name, namespaceUri);
+            return FindSimpleType(qualifiedName);
+        }
+
+        /// <summary>
+        /// Finds the specified attribute in the schema. This method only checks
+        /// the attributes defined in the root of the schema.
+        /// </summary>
+        public XmlSchemaAttribute FindAttribute(string name)
+        {
+            foreach (XmlSchemaAttribute attribute in schema.Attributes.Values)
+            {
+                if (attribute.Name == name)
+                {
+                    return attribute;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Finds the schema group with the specified name.
+        /// </summary>
+        public XmlSchemaGroup FindGroup(string name)
+        {
+            if (name != null)
+            {
+                foreach (XmlSchemaObject schemaObject in schema.Groups.Values)
+                {
+                    XmlSchemaGroup group = schemaObject as XmlSchemaGroup;
+                    if (group != null)
+                    {
+                        if (group.Name == name)
+                        {
+                            return group;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Takes the name and creates a qualified name using the namespace of this
+        /// schema.
+        /// </summary>
+        /// <remarks>If the name is of the form myprefix:mytype then the correct 
+        /// namespace is determined from the prefix. If the name is not of this
+        /// form then no prefix is added.</remarks>
+        public QualifiedName CreateQualifiedName(string name)
+        {
+            int index = name.IndexOf(":");
+            if (index >= 0)
+            {
+                string prefix = name.Substring(0, index);
+                name = name.Substring(index + 1);
+                foreach (XmlQualifiedName xmlQualifiedName in schema.Namespaces.ToArray())
+                {
+                    if (xmlQualifiedName.Name == prefix)
+                    {
+                        return new QualifiedName(name, xmlQualifiedName.Namespace, prefix);
+                    }
+                }
+            }
+
+            // Default behaviour just return the name with the namespace uri.
+            return new QualifiedName(name, namespaceUri);
+        }
+
+        /// <summary>
+        /// Converts the element to a complex type if possible.
+        /// </summary>
+        public XmlSchemaComplexType GetElementAsComplexType(XmlSchemaElement element)
+        {
+            XmlSchemaComplexType complexType = element.SchemaType as XmlSchemaComplexType;
+            if (complexType == null)
+            {
+                complexType = FindNamedType(schema, element.SchemaTypeName);
+            }
+            return complexType;
+        }
+
+        /// <summary>
+        /// Handler for schema validation errors.
+        /// </summary>
+        void SchemaValidation(object source, ValidationEventArgs e)
+        {
+            // Do nothing.
+        }
+
+        /// <summary>
+        /// Loads the schema.
+        /// </summary>
+        void ReadSchema(XmlReader reader)
+        {
+            try
+            {
+                schema = XmlSchema.Read(reader, new ValidationEventHandler(SchemaValidation));
+                schema.Compile(new ValidationEventHandler(SchemaValidation));
+
+                namespaceUri = schema.TargetNamespace;
+            }
+            finally
+            {
+                reader.Close();
+            }
+        }
+
+        void ReadSchema(string baseUri, TextReader reader)
+        {
+            XmlTextReader xmlReader = new XmlTextReader(baseUri, reader);
+
+            // Setting the resolver to null allows us to
+            // load the xhtml1-strict.xsd without any exceptions if
+            // the referenced dtds exist in the same folder as the .xsd
+            // file.  If this is not set to null the dtd files are looked
+            // for in the assembly's folder.
+            xmlReader.XmlResolver = null;
+            ReadSchema(xmlReader);
+        }
+
+        /// <summary>
+        /// Finds an element in the schema.
+        /// </summary>
+        /// <remarks>
+        /// Only looks at the elements that are defined in the 
+        /// root of the schema so it will not find any elements
+        /// that are defined inside any complex types.
+        /// </remarks>
+        XmlSchemaElement FindElement(XmlQualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+            foreach (XmlSchemaElement element in schema.Elements.Values)
+            {
+                if (name.Equals(element.QualifiedName))
+                {
+                    matchedElement = element;
+                    break;
+                }
+            }
+
+            return matchedElement;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaElement element, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaComplexType complexType = GetElementAsComplexType(element);
+
+            if (complexType != null)
+            {
+                data = GetChildElementCompletionData(complexType, prefix);
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexType complexType, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaSequence sequence = complexType.Particle as XmlSchemaSequence;
+            XmlSchemaChoice choice = complexType.Particle as XmlSchemaChoice;
+            XmlSchemaGroupRef groupRef = complexType.Particle as XmlSchemaGroupRef;
+            XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent;
+            XmlSchemaAll all = complexType.Particle as XmlSchemaAll;
+
+            if (sequence != null)
+            {
+                data = GetChildElementCompletionData(sequence.Items, prefix);
+            }
+            else if (choice != null)
+            {
+                data = GetChildElementCompletionData(choice.Items, prefix);
+            }
+            else if (complexContent != null)
+            {
+                data = GetChildElementCompletionData(complexContent, prefix);
+            }
+            else if (groupRef != null)
+            {
+                data = GetChildElementCompletionData(groupRef, prefix);
+            }
+            else if (all != null)
+            {
+                data = GetChildElementCompletionData(all.Items, prefix);
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaObjectCollection items, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            foreach (XmlSchemaObject schemaObject in items)
+            {
+
+                XmlSchemaElement childElement = schemaObject as XmlSchemaElement;
+                XmlSchemaSequence childSequence = schemaObject as XmlSchemaSequence;
+                XmlSchemaChoice childChoice = schemaObject as XmlSchemaChoice;
+                XmlSchemaGroupRef groupRef = schemaObject as XmlSchemaGroupRef;
+
+                if (childElement != null)
+                {
+                    string name = childElement.Name;
+                    if (name == null)
+                    {
+                        name = childElement.RefName.Name;
+                        XmlSchemaElement element = FindElement(childElement.RefName);
+                        if (element != null)
+                        {
+                            if (element.IsAbstract)
+                            {
+                                AddSubstitionGroupElements(data, element.QualifiedName, prefix);
+                            }
+                            else
+                            {
+                                AddElement(data, name, prefix, element.Annotation);
+                            }
+                        }
+                        else
+                        {
+                            AddElement(data, name, prefix, childElement.Annotation);
+                        }
+                    }
+                    else
+                    {
+                        AddElement(data, name, prefix, childElement.Annotation);
+                    }
+                }
+                else if (childSequence != null)
+                {
+                    AddElements(data, GetChildElementCompletionData(childSequence.Items, prefix));
+                }
+                else if (childChoice != null)
+                {
+                    AddElements(data, GetChildElementCompletionData(childChoice.Items, prefix));
+                }
+                else if (groupRef != null)
+                {
+                    AddElements(data, GetChildElementCompletionData(groupRef, prefix));
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContent complexContent, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
+            if (extension != null)
+            {
+                data = GetChildElementCompletionData(extension, prefix);
+            }
+            else
+            {
+                XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
+                if (restriction != null)
+                {
+                    data = GetChildElementCompletionData(restriction, prefix);
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContentExtension extension, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName);
+            if (complexType != null)
+            {
+                data = GetChildElementCompletionData(complexType, prefix);
+            }
+
+            // Add any elements.
+            if (extension.Particle != null)
+            {
+                XmlSchemaSequence sequence = extension.Particle as XmlSchemaSequence;
+                XmlSchemaChoice choice = extension.Particle as XmlSchemaChoice;
+                XmlSchemaGroupRef groupRef = extension.Particle as XmlSchemaGroupRef;
+
+                if (sequence != null)
+                {
+                    data.AddRange(GetChildElementCompletionData(sequence.Items, prefix));
+                }
+                else if (choice != null)
+                {
+                    data.AddRange(GetChildElementCompletionData(choice.Items, prefix));
+                }
+                else if (groupRef != null)
+                {
+                    data.AddRange(GetChildElementCompletionData(groupRef, prefix));
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaGroupRef groupRef, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaGroup group = FindGroup(groupRef.RefName.Name);
+            if (group != null)
+            {
+                XmlSchemaSequence sequence = group.Particle as XmlSchemaSequence;
+                XmlSchemaChoice choice = group.Particle as XmlSchemaChoice;
+
+                if (sequence != null)
+                {
+                    data = GetChildElementCompletionData(sequence.Items, prefix);
+                }
+                else if (choice != null)
+                {
+                    data = GetChildElementCompletionData(choice.Items, prefix);
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContentRestriction restriction, string prefix)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            // Add any elements.
+            if (restriction.Particle != null)
+            {
+                XmlSchemaSequence sequence = restriction.Particle as XmlSchemaSequence;
+                XmlSchemaChoice choice = restriction.Particle as XmlSchemaChoice;
+                XmlSchemaGroupRef groupRef = restriction.Particle as XmlSchemaGroupRef;
+
+                if (sequence != null)
+                {
+                    data = GetChildElementCompletionData(sequence.Items, prefix);
+                }
+                else if (choice != null)
+                {
+                    data = GetChildElementCompletionData(choice.Items, prefix);
+                }
+                else if (groupRef != null)
+                {
+                    data = GetChildElementCompletionData(groupRef, prefix);
+                }
+            }
+
+            return data;
+        }
+
+        /// <summary>
+        /// Adds an element completion data to the collection if it does not 
+        /// already exist.
+        /// </summary>
+        void AddElement(XmlCompletionDataCollection data, string name, string prefix, string documentation)
+        {
+            if (!data.Contains(name))
+            {
+                if (prefix.Length > 0)
+                {
+                    name = String.Concat(prefix, ":", name);
+                }
+                XmlCompletionData completionData = new XmlCompletionData(name, documentation);
+                data.Add(completionData);
+            }
+        }
+
+        /// <summary>
+        /// Adds an element completion data to the collection if it does not 
+        /// already exist.
+        /// </summary>
+        void AddElement(XmlCompletionDataCollection data, string name, string prefix, XmlSchemaAnnotation annotation)
+        {
+            // Get any annotation documentation.
+            string documentation = GetDocumentation(annotation);
+
+            AddElement(data, name, prefix, documentation);
+        }
+
+        /// <summary>
+        /// Adds elements to the collection if it does not already exist.
+        /// </summary>
+        void AddElements(XmlCompletionDataCollection lhs, XmlCompletionDataCollection rhs)
+        {
+            foreach (XmlCompletionData data in rhs)
+            {
+                if (!lhs.Contains(data))
+                {
+                    lhs.Add(data);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the documentation from the annotation element.
+        /// </summary>
+        /// <remarks>
+        /// All documentation elements are added.  All text nodes inside
+        /// the documentation element are added.
+        /// </remarks>
+        string GetDocumentation(XmlSchemaAnnotation annotation)
+        {
+            string documentation = String.Empty;
+
+            if (annotation != null)
+            {
+                StringBuilder documentationBuilder = new StringBuilder();
+                foreach (XmlSchemaObject schemaObject in annotation.Items)
+                {
+                    XmlSchemaDocumentation schemaDocumentation = schemaObject as XmlSchemaDocumentation;
+                    if (schemaDocumentation != null)
+                    {
+                        foreach (XmlNode node in schemaDocumentation.Markup)
+                        {
+                            XmlText textNode = node as XmlText;
+                            if (textNode != null)
+                            {
+                                if (textNode.Data != null)
+                                {
+                                    if (textNode.Data.Length > 0)
+                                    {
+                                        documentationBuilder.Append(textNode.Data);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                documentation = documentationBuilder.ToString();
+            }
+
+            return documentation;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaElement element)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaComplexType complexType = GetElementAsComplexType(element);
+
+            if (complexType != null)
+            {
+                data.AddRange(GetAttributeCompletionData(complexType));
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexContentRestriction restriction)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            data.AddRange(GetAttributeCompletionData(restriction.Attributes));
+
+            XmlSchemaComplexType baseComplexType = FindNamedType(schema, restriction.BaseTypeName);
+            if (baseComplexType != null)
+            {
+                data.AddRange(GetAttributeCompletionData(baseComplexType));
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexType complexType)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            data = GetAttributeCompletionData(complexType.Attributes);
+
+            // Add any complex content attributes.
+            XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent;
+            if (complexContent != null)
+            {
+                XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
+                XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
+                if (extension != null)
+                {
+                    data.AddRange(GetAttributeCompletionData(extension));
+                }
+                else if (restriction != null)
+                {
+                    data.AddRange(GetAttributeCompletionData(restriction));
+                }
+            }
+            else
+            {
+                XmlSchemaSimpleContent simpleContent = complexType.ContentModel as XmlSchemaSimpleContent;
+                if (simpleContent != null)
+                {
+                    data.AddRange(GetAttributeCompletionData(simpleContent));
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexContentExtension extension)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            data.AddRange(GetAttributeCompletionData(extension.Attributes));
+            XmlSchemaComplexType baseComplexType = FindNamedType(schema, extension.BaseTypeName);
+            if (baseComplexType != null)
+            {
+                data.AddRange(GetAttributeCompletionData(baseComplexType));
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaSimpleContent simpleContent)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaSimpleContentExtension extension = simpleContent.Content as XmlSchemaSimpleContentExtension;
+            if (extension != null)
+            {
+                data.AddRange(GetAttributeCompletionData(extension));
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaSimpleContentExtension extension)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            data.AddRange(GetAttributeCompletionData(extension.Attributes));
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaObjectCollection attributes)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            foreach (XmlSchemaObject schemaObject in attributes)
+            {
+                XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute;
+                XmlSchemaAttributeGroupRef attributeGroupRef = schemaObject as XmlSchemaAttributeGroupRef;
+                if (attribute != null)
+                {
+                    if (!IsProhibitedAttribute(attribute))
+                    {
+                        AddAttribute(data, attribute);
+                    }
+                    else
+                    {
+                        prohibitedAttributes.Add(attribute);
+                    }
+                }
+                else if (attributeGroupRef != null)
+                {
+                    data.AddRange(GetAttributeCompletionData(attributeGroupRef));
+                }
+            }
+            return data;
+        }
+
+        /// <summary>
+        /// Checks that the attribute is prohibited or has been flagged
+        /// as prohibited previously. 
+        /// </summary>
+        bool IsProhibitedAttribute(XmlSchemaAttribute attribute)
+        {
+            bool prohibited = false;
+            if (attribute.Use == XmlSchemaUse.Prohibited)
+            {
+                prohibited = true;
+            }
+            else
+            {
+                foreach (XmlSchemaAttribute prohibitedAttribute in prohibitedAttributes)
+                {
+                    if (prohibitedAttribute.QualifiedName == attribute.QualifiedName)
+                    {
+                        prohibited = true;
+                        break;
+                    }
+                }
+            }
+
+            return prohibited;
+        }
+
+        /// <summary>
+        /// Adds an attribute to the completion data collection.
+        /// </summary>
+        /// <remarks>
+        /// Note the special handling of xml:lang attributes.
+        /// </remarks>
+        void AddAttribute(XmlCompletionDataCollection data, XmlSchemaAttribute attribute)
+        {
+            string name = attribute.Name;
+            if (name == null)
+            {
+                if (attribute.RefName.Namespace == "http://www.w3.org/XML/1998/namespace")
+                {
+                    name = String.Concat("xml:", attribute.RefName.Name);
+                }
+            }
+
+            if (name != null)
+            {
+                string documentation = GetDocumentation(attribute.Annotation);
+                XmlCompletionData completionData = new XmlCompletionData(name, documentation, XmlCompletionData.DataType.XmlAttribute);
+                data.Add(completionData);
+            }
+        }
+
+        /// <summary>
+        /// Gets attribute completion data from a group ref.
+        /// </summary>
+        XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaAttributeGroupRef groupRef)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+            XmlSchemaAttributeGroup group = FindAttributeGroup(schema, groupRef.RefName.Name);
+            if (group != null)
+            {
+                data = GetAttributeCompletionData(group.Attributes);
+            }
+
+            return data;
+        }
+
+        static XmlSchemaComplexType FindNamedType(XmlSchema schema, XmlQualifiedName name)
+        {
+            XmlSchemaComplexType matchedComplexType = null;
+
+            if (name != null)
+            {
+                foreach (XmlSchemaObject schemaObject in schema.Items)
+                {
+                    XmlSchemaComplexType complexType = schemaObject as XmlSchemaComplexType;
+                    if (complexType != null)
+                    {
+                        if (complexType.QualifiedName == name)
+                        {
+                            matchedComplexType = complexType;
+                            break;
+                        }
+                    }
+                }
+
+                // Try included schemas.
+                if (matchedComplexType == null)
+                {
+                    foreach (XmlSchemaExternal external in schema.Includes)
+                    {
+                        XmlSchemaInclude include = external as XmlSchemaInclude;
+                        if (include != null)
+                        {
+                            if (include.Schema != null)
+                            {
+                                matchedComplexType = FindNamedType(include.Schema, name);
+                            }
+                        }
+                    }
+                }
+            }
+
+            return matchedComplexType;
+        }
+
+        /// <summary>
+        /// Finds an element that matches the specified <paramref name="name"/>
+        /// from the children of the given <paramref name="element"/>.
+        /// </summary>
+        XmlSchemaElement FindChildElement(XmlSchemaElement element, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            XmlSchemaComplexType complexType = GetElementAsComplexType(element);
+            if (complexType != null)
+            {
+                matchedElement = FindChildElement(complexType, name);
+            }
+
+            return matchedElement;
+        }
+
+        XmlSchemaElement FindChildElement(XmlSchemaComplexType complexType, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            XmlSchemaSequence sequence = complexType.Particle as XmlSchemaSequence;
+            XmlSchemaChoice choice = complexType.Particle as XmlSchemaChoice;
+            XmlSchemaGroupRef groupRef = complexType.Particle as XmlSchemaGroupRef;
+            XmlSchemaAll all = complexType.Particle as XmlSchemaAll;
+            XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent;
+
+            if (sequence != null)
+            {
+                matchedElement = FindElement(sequence.Items, name);
+            }
+            else if (choice != null)
+            {
+                matchedElement = FindElement(choice.Items, name);
+            }
+            else if (complexContent != null)
+            {
+                XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
+                XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
+                if (extension != null)
+                {
+                    matchedElement = FindChildElement(extension, name);
+                }
+                else if (restriction != null)
+                {
+                    matchedElement = FindChildElement(restriction, name);
+                }
+            }
+            else if (groupRef != null)
+            {
+                matchedElement = FindElement(groupRef, name);
+            }
+            else if (all != null)
+            {
+                matchedElement = FindElement(all.Items, name);
+            }
+
+            return matchedElement;
+        }
+
+        /// <summary>
+        /// Finds the named child element contained in the extension element.
+        /// </summary>
+        XmlSchemaElement FindChildElement(XmlSchemaComplexContentExtension extension, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName);
+            if (complexType != null)
+            {
+                matchedElement = FindChildElement(complexType, name);
+
+                if (matchedElement == null)
+                {
+
+                    XmlSchemaSequence sequence = extension.Particle as XmlSchemaSequence;
+                    XmlSchemaChoice choice = extension.Particle as XmlSchemaChoice;
+                    XmlSchemaGroupRef groupRef = extension.Particle as XmlSchemaGroupRef;
+
+                    if (sequence != null)
+                    {
+                        matchedElement = FindElement(sequence.Items, name);
+                    }
+                    else if (choice != null)
+                    {
+                        matchedElement = FindElement(choice.Items, name);
+                    }
+                    else if (groupRef != null)
+                    {
+                        matchedElement = FindElement(groupRef, name);
+                    }
+                }
+            }
+
+            return matchedElement;
+        }
+
+        /// <summary>
+        /// Finds the named child element contained in the restriction element.
+        /// </summary>
+        XmlSchemaElement FindChildElement(XmlSchemaComplexContentRestriction restriction, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+            XmlSchemaSequence sequence = restriction.Particle as XmlSchemaSequence;
+            XmlSchemaGroupRef groupRef = restriction.Particle as XmlSchemaGroupRef;
+
+            if (sequence != null)
+            {
+                matchedElement = FindElement(sequence.Items, name);
+            }
+            else if (groupRef != null)
+            {
+                matchedElement = FindElement(groupRef, name);
+            }
+
+            return matchedElement;
+        }
+
+        /// <summary>
+        /// Finds the element in the collection of schema objects.
+        /// </summary>
+        XmlSchemaElement FindElement(XmlSchemaObjectCollection items, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            foreach (XmlSchemaObject schemaObject in items)
+            {
+                XmlSchemaElement element = schemaObject as XmlSchemaElement;
+                XmlSchemaSequence sequence = schemaObject as XmlSchemaSequence;
+                XmlSchemaChoice choice = schemaObject as XmlSchemaChoice;
+                XmlSchemaGroupRef groupRef = schemaObject as XmlSchemaGroupRef;
+
+                if (element != null)
+                {
+                    if (element.Name != null)
+                    {
+                        if (name.Name == element.Name)
+                        {
+                            matchedElement = element;
+                        }
+                    }
+                    else if (element.RefName != null)
+                    {
+                        if (name.Name == element.RefName.Name)
+                        {
+                            matchedElement = FindElement(element.RefName);
+                        }
+                        else
+                        {
+                            // Abstract element?
+                            XmlSchemaElement abstractElement = FindElement(element.RefName);
+                            if (abstractElement != null && abstractElement.IsAbstract)
+                            {
+                                matchedElement = FindSubstitutionGroupElement(abstractElement.QualifiedName, name);
+                            }
+                        }
+                    }
+                }
+                else if (sequence != null)
+                {
+                    matchedElement = FindElement(sequence.Items, name);
+                }
+                else if (choice != null)
+                {
+                    matchedElement = FindElement(choice.Items, name);
+                }
+                else if (groupRef != null)
+                {
+                    matchedElement = FindElement(groupRef, name);
+                }
+
+                // Did we find a match?
+                if (matchedElement != null)
+                {
+                    break;
+                }
+            }
+
+            return matchedElement;
+        }
+
+        XmlSchemaElement FindElement(XmlSchemaGroupRef groupRef, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            XmlSchemaGroup group = FindGroup(groupRef.RefName.Name);
+            if (group != null)
+            {
+                XmlSchemaSequence sequence = group.Particle as XmlSchemaSequence;
+                XmlSchemaChoice choice = group.Particle as XmlSchemaChoice;
+
+                if (sequence != null)
+                {
+                    matchedElement = FindElement(sequence.Items, name);
+                }
+                else if (choice != null)
+                {
+                    matchedElement = FindElement(choice.Items, name);
+                }
+            }
+
+            return matchedElement;
+        }
+
+        static XmlSchemaAttributeGroup FindAttributeGroup(XmlSchema schema, string name)
+        {
+            XmlSchemaAttributeGroup matchedGroup = null;
+
+            if (name != null)
+            {
+                foreach (XmlSchemaObject schemaObject in schema.Items)
+                {
+
+                    XmlSchemaAttributeGroup group = schemaObject as XmlSchemaAttributeGroup;
+                    if (group != null)
+                    {
+                        if (group.Name == name)
+                        {
+                            matchedGroup = group;
+                            break;
+                        }
+                    }
+                }
+
+                // Try included schemas.
+                if (matchedGroup == null)
+                {
+                    foreach (XmlSchemaExternal external in schema.Includes)
+                    {
+                        XmlSchemaInclude include = external as XmlSchemaInclude;
+                        if (include != null)
+                        {
+                            if (include.Schema != null)
+                            {
+                                matchedGroup = FindAttributeGroup(include.Schema, name);
+                            }
+                        }
+                    }
+                }
+            }
+
+            return matchedGroup;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaElement element, string name)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaComplexType complexType = GetElementAsComplexType(element);
+            if (complexType != null)
+            {
+                XmlSchemaAttribute attribute = FindAttribute(complexType, name);
+                if (attribute != null)
+                {
+                    data.AddRange(GetAttributeValueCompletionData(attribute));
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaAttribute attribute)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            if (attribute.SchemaType != null)
+            {
+                XmlSchemaSimpleTypeRestriction simpleTypeRestriction = attribute.SchemaType.Content as XmlSchemaSimpleTypeRestriction;
+                if (simpleTypeRestriction != null)
+                {
+                    data.AddRange(GetAttributeValueCompletionData(simpleTypeRestriction));
+                }
+            }
+            else if (attribute.AttributeSchemaType != null)
+            {
+                XmlSchemaSimpleType simpleType = attribute.AttributeSchemaType as XmlSchemaSimpleType;
+
+                if (simpleType != null)
+                {
+                    if (simpleType.Name == "boolean")
+                    {
+                        data.AddRange(GetBooleanAttributeValueCompletionData());
+                    }
+                    else
+                    {
+                        data.AddRange(GetAttributeValueCompletionData(simpleType));
+                    }
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeRestriction simpleTypeRestriction)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            foreach (XmlSchemaObject schemaObject in simpleTypeRestriction.Facets)
+            {
+                XmlSchemaEnumerationFacet enumFacet = schemaObject as XmlSchemaEnumerationFacet;
+                if (enumFacet != null)
+                {
+                    AddAttributeValue(data, enumFacet.Value, enumFacet.Annotation);
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeUnion union)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            foreach (XmlSchemaObject schemaObject in union.BaseTypes)
+            {
+                XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType;
+                if (simpleType != null)
+                {
+                    data.AddRange(GetAttributeValueCompletionData(simpleType));
+                }
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleType simpleType)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            XmlSchemaSimpleTypeRestriction simpleTypeRestriction = simpleType.Content as XmlSchemaSimpleTypeRestriction;
+            XmlSchemaSimpleTypeUnion union = simpleType.Content as XmlSchemaSimpleTypeUnion;
+            XmlSchemaSimpleTypeList list = simpleType.Content as XmlSchemaSimpleTypeList;
+
+            if (simpleTypeRestriction != null)
+            {
+                data.AddRange(GetAttributeValueCompletionData(simpleTypeRestriction));
+            }
+            else if (union != null)
+            {
+                data.AddRange(GetAttributeValueCompletionData(union));
+            }
+            else if (list != null)
+            {
+                data.AddRange(GetAttributeValueCompletionData(list));
+            }
+
+            return data;
+        }
+
+        XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeList list)
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            if (list.ItemType != null)
+            {
+                data.AddRange(GetAttributeValueCompletionData(list.ItemType));
+            }
+            else if (list.ItemTypeName != null)
+            {
+                XmlSchemaSimpleType simpleType = FindSimpleType(list.ItemTypeName);
+                if (simpleType != null)
+                {
+                    data.AddRange(GetAttributeValueCompletionData(simpleType));
+                }
+            }
+
+            return data;
+        }
+
+        /// <summary>
+        /// Gets the set of attribute values for an xs:boolean type.
+        /// </summary>
+        XmlCompletionDataCollection GetBooleanAttributeValueCompletionData()
+        {
+            XmlCompletionDataCollection data = new XmlCompletionDataCollection();
+
+            AddAttributeValue(data, "0");
+            AddAttributeValue(data, "1");
+            AddAttributeValue(data, "true");
+            AddAttributeValue(data, "false");
+
+            return data;
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaComplexType complexType, string name)
+        {
+            XmlSchemaAttribute matchedAttribute = null;
+
+            matchedAttribute = FindAttribute(complexType.Attributes, name);
+
+            if (matchedAttribute == null)
+            {
+                XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent;
+                if (complexContent != null)
+                {
+                    matchedAttribute = FindAttribute(complexContent, name);
+                }
+            }
+
+            return matchedAttribute;
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaObjectCollection schemaObjects, string name)
+        {
+            XmlSchemaAttribute matchedAttribute = null;
+
+            foreach (XmlSchemaObject schemaObject in schemaObjects)
+            {
+                XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute;
+                XmlSchemaAttributeGroupRef groupRef = schemaObject as XmlSchemaAttributeGroupRef;
+
+                if (attribute != null)
+                {
+                    if (attribute.Name == name)
+                    {
+                        matchedAttribute = attribute;
+                        break;
+                    }
+                }
+                else if (groupRef != null)
+                {
+                    matchedAttribute = FindAttribute(groupRef, name);
+                    if (matchedAttribute != null)
+                    {
+                        break;
+                    }
+                }
+            }
+
+            return matchedAttribute;
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaAttributeGroupRef groupRef, string name)
+        {
+            XmlSchemaAttribute matchedAttribute = null;
+
+            if (groupRef.RefName != null)
+            {
+                XmlSchemaAttributeGroup group = FindAttributeGroup(schema, groupRef.RefName.Name);
+                if (group != null)
+                {
+                    matchedAttribute = FindAttribute(group.Attributes, name);
+                }
+            }
+
+            return matchedAttribute;
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaComplexContent complexContent, string name)
+        {
+            XmlSchemaAttribute matchedAttribute = null;
+
+            XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
+            XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
+
+            if (extension != null)
+            {
+                matchedAttribute = FindAttribute(extension, name);
+            }
+            else if (restriction != null)
+            {
+                matchedAttribute = FindAttribute(restriction, name);
+            }
+
+            return matchedAttribute;
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentExtension extension, string name)
+        {
+            return FindAttribute(extension.Attributes, name);
+        }
+
+        XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentRestriction restriction, string name)
+        {
+            XmlSchemaAttribute matchedAttribute = FindAttribute(restriction.Attributes, name);
+
+            if (matchedAttribute == null)
+            {
+                XmlSchemaComplexType complexType = FindNamedType(schema, restriction.BaseTypeName);
+                if (complexType != null)
+                {
+                    matchedAttribute = FindAttribute(complexType, name);
+                }
+            }
+
+            return matchedAttribute;
+        }
+
+        /// <summary>
+        /// Adds an attribute value to the completion data collection.
+        /// </summary>
+        void AddAttributeValue(XmlCompletionDataCollection data, string valueText)
+        {
+            XmlCompletionData completionData = new XmlCompletionData(valueText, XmlCompletionData.DataType.XmlAttributeValue);
+            data.Add(completionData);
+        }
+
+        /// <summary>
+        /// Adds an attribute value to the completion data collection.
+        /// </summary>
+        void AddAttributeValue(XmlCompletionDataCollection data, string valueText, XmlSchemaAnnotation annotation)
+        {
+            string documentation = GetDocumentation(annotation);
+            XmlCompletionData completionData = new XmlCompletionData(valueText, documentation, XmlCompletionData.DataType.XmlAttributeValue);
+            data.Add(completionData);
+        }
+
+        /// <summary>
+        /// Adds an attribute value to the completion data collection.
+        /// </summary>
+        void AddAttributeValue(XmlCompletionDataCollection data, string valueText, string description)
+        {
+            XmlCompletionData completionData = new XmlCompletionData(valueText, description, XmlCompletionData.DataType.XmlAttributeValue);
+            data.Add(completionData);
+        }
+
+        XmlSchemaSimpleType FindSimpleType(XmlQualifiedName name)
+        {
+            XmlSchemaSimpleType matchedSimpleType = null;
+
+            foreach (XmlSchemaObject schemaObject in schema.SchemaTypes.Values)
+            {
+                XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType;
+                if (simpleType != null)
+                {
+                    if (simpleType.QualifiedName == name)
+                    {
+                        matchedSimpleType = simpleType;
+                        break;
+                    }
+                }
+            }
+
+            return matchedSimpleType;
+        }
+
+        /// <summary>
+        /// Adds any elements that have the specified substitution group.
+        /// </summary>
+        void AddSubstitionGroupElements(XmlCompletionDataCollection data, XmlQualifiedName group, string prefix)
+        {
+            foreach (XmlSchemaElement element in schema.Elements.Values)
+            {
+                if (element.SubstitutionGroup == group)
+                {
+                    AddElement(data, element.Name, prefix, element.Annotation);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Looks for the substitution group element of the specified name.
+        /// </summary>
+        XmlSchemaElement FindSubstitutionGroupElement(XmlQualifiedName group, QualifiedName name)
+        {
+            XmlSchemaElement matchedElement = null;
+
+            foreach (XmlSchemaElement element in schema.Elements.Values)
+            {
+                if (element.SubstitutionGroup == group)
+                {
+                    if (element.Name != null)
+                    {
+                        if (element.Name == name.Name)
+                        {
+                            matchedElement = element;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return matchedElement;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionDataCollection.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionDataCollection.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaCompletionDataCollection.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,431 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using ICSharpCode.TextEditor.Gui.CompletionWindow;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    ///   A collection that stores <see cref='XmlSchemaCompletionData'/> objects.
+    /// </summary>
+    [Serializable()]
+    public class XmlSchemaCompletionDataCollection : System.Collections.CollectionBase
+    {
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        public XmlSchemaCompletionDataCollection()
+        {
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlSchemaCompletionDataCollection'/> based on another <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///   A <see cref='XmlSchemaCompletionDataCollection'/> from which the contents are copied
+        /// </param>
+        public XmlSchemaCompletionDataCollection(XmlSchemaCompletionDataCollection val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Initializes a new instance of <see cref='XmlSchemaCompletionDataCollection'/> containing any array of <see cref='XmlSchemaCompletionData'/> objects.
+        /// </summary>
+        /// <param name='val'>
+        ///       A array of <see cref='XmlSchemaCompletionData'/> objects with which to intialize the collection
+        /// </param>
+        public XmlSchemaCompletionDataCollection(XmlSchemaCompletionData[] val)
+        {
+            this.AddRange(val);
+        }
+
+        /// <summary>
+        ///   Represents the entry at the specified index of the <see cref='XmlSchemaCompletionData'/>.
+        /// </summary>
+        /// <param name='index'>The zero-based index of the entry to locate in the collection.</param>
+        /// <value>The entry at the specified index of the collection.</value>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='index'/> is outside the valid range of indexes for the collection.</exception>
+        public XmlSchemaCompletionData this[int index]
+        {
+            get
+            {
+                return ((XmlSchemaCompletionData)(List[index]));
+            }
+            set
+            {
+                List[index] = value;
+            }
+        }
+
+        public ICompletionData[] GetNamespaceCompletionData()
+        {
+            List<ICompletionData> completionItems = new List<ICompletionData>();
+
+            foreach (XmlSchemaCompletionData schema in this)
+            {
+                XmlCompletionData completionData = new XmlCompletionData(schema.NamespaceUri, XmlCompletionData.DataType.NamespaceUri);
+                completionItems.Add(completionData);
+            }
+
+            return completionItems.ToArray();
+        }
+
+        /// <summary>
+        ///   Represents the <see cref='XmlSchemaCompletionData'/> entry with the specified namespace URI.
+        /// </summary>
+        /// <param name='namespaceUri'>The schema's namespace URI.</param>
+        /// <value>The entry with the specified namespace URI.</value>
+        public XmlSchemaCompletionData this[string namespaceUri]
+        {
+            get
+            {
+                return GetItem(namespaceUri);
+            }
+        }
+
+        /// <summary>
+        ///   Adds a <see cref='XmlSchemaCompletionData'/> with the specified value to the 
+        ///   <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlSchemaCompletionData'/> to add.</param>
+        /// <returns>The index at which the new element was inserted.</returns>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.AddRange'/>
+        public int Add(XmlSchemaCompletionData val)
+        {
+            return List.Add(val);
+        }
+
+        /// <summary>
+        ///   Copies the elements of an array to the end of the <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>
+        ///    An array of type <see cref='XmlSchemaCompletionData'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.Add'/>
+        public void AddRange(XmlSchemaCompletionData[] val)
+        {
+            for (int i = 0; i < val.Length; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Adds the contents of another <see cref='XmlSchemaCompletionDataCollection'/> to the end of the collection.
+        /// </summary>
+        /// <param name='val'>
+        ///    A <see cref='XmlSchemaCompletionDataCollection'/> containing the objects to add to the collection.
+        /// </param>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.Add'/>
+        public void AddRange(XmlSchemaCompletionDataCollection val)
+        {
+            for (int i = 0; i < val.Count; i++)
+            {
+                this.Add(val[i]);
+            }
+        }
+
+        /// <summary>
+        ///   Gets a value indicating whether the 
+        ///    <see cref='XmlSchemaCompletionDataCollection'/> contains the specified <see cref='XmlSchemaCompletionData'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlSchemaCompletionData'/> to locate.</param>
+        /// <returns>
+        /// <see langword='true'/> if the <see cref='XmlSchemaCompletionData'/> is contained in the collection; 
+        ///   otherwise, <see langword='false'/>.
+        /// </returns>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.IndexOf'/>
+        public bool Contains(XmlSchemaCompletionData val)
+        {
+            return List.Contains(val);
+        }
+
+        /// <summary>
+        ///   Copies the <see cref='XmlSchemaCompletionDataCollection'/> values to a one-dimensional <see cref='Array'/> instance at the 
+        ///    specified index.
+        /// </summary>
+        /// <param name='array'>The one-dimensional <see cref='Array'/> that is the destination of the values copied from <see cref='XmlSchemaCompletionDataCollection'/>.</param>
+        /// <param name='index'>The index in <paramref name='array'/> where copying begins.</param>
+        /// <exception cref='ArgumentException'>
+        ///   <para><paramref name='array'/> is multidimensional.</para>
+        ///   <para>-or-</para>
+        ///   <para>The number of elements in the <see cref='XmlSchemaCompletionDataCollection'/> is greater than
+        ///         the available space between <paramref name='arrayIndex'/> and the end of
+        ///         <paramref name='array'/>.</para>
+        /// </exception>
+        /// <exception cref='ArgumentNullException'><paramref name='array'/> is <see langword='null'/>. </exception>
+        /// <exception cref='ArgumentOutOfRangeException'><paramref name='arrayIndex'/> is less than <paramref name='array'/>'s lowbound. </exception>
+        /// <seealso cref='Array'/>
+        public void CopyTo(XmlSchemaCompletionData[] array, int index)
+        {
+            List.CopyTo(array, index);
+        }
+
+        /// <summary>
+        ///    Returns the index of a <see cref='XmlSchemaCompletionData'/> in 
+        ///       the <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlSchemaCompletionData'/> to locate.</param>
+        /// <returns>
+        ///   The index of the <see cref='XmlSchemaCompletionData'/> of <paramref name='val'/> in the 
+        ///   <see cref='XmlSchemaCompletionDataCollection'/>, if found; otherwise, -1.
+        /// </returns>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.Contains'/>
+        public int IndexOf(XmlSchemaCompletionData val)
+        {
+            return List.IndexOf(val);
+        }
+
+        /// <summary>
+        ///   Inserts a <see cref='XmlSchemaCompletionData'/> into the <see cref='XmlSchemaCompletionDataCollection'/> at the specified index.
+        /// </summary>
+        /// <param name='index'>The zero-based index where <paramref name='val'/> should be inserted.</param>
+        /// <param name='val'>The <see cref='XmlSchemaCompletionData'/> to insert.</param>
+        /// <seealso cref='XmlSchemaCompletionDataCollection.Add'/>
+        public void Insert(int index, XmlSchemaCompletionData val)
+        {
+            List.Insert(index, val);
+        }
+
+        /// <summary>
+        ///  Returns an enumerator that can iterate through the <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        public new XmlSchemaCompletionDataEnumerator GetEnumerator()
+        {
+            return new XmlSchemaCompletionDataEnumerator(this);
+        }
+
+        /// <summary>
+        ///   Removes a specific <see cref='XmlSchemaCompletionData'/> from the <see cref='XmlSchemaCompletionDataCollection'/>.
+        /// </summary>
+        /// <param name='val'>The <see cref='XmlSchemaCompletionData'/> to remove from the <see cref='XmlSchemaCompletionDataCollection'/>.</param>
+        /// <exception cref='ArgumentException'><paramref name='val'/> is not found in the Collection.</exception>
+        public void Remove(XmlSchemaCompletionData val)
+        {
+            List.Remove(val);
+        }
+
+        /// <summary>
+        /// Gets the schema completion data with the same filename.
+        /// </summary>
+        /// <returns><see langword="null"/> if no matching schema found.</returns>
+        public XmlSchemaCompletionData GetSchemaFromFileName(string fileName)
+        {
+            foreach (XmlSchemaCompletionData schema in this)
+            {
+                if (IsEqualFileName(schema.FileName, fileName))
+                {
+                    return schema;
+                }
+            }
+            return null;
+        }
+
+        static string NormalizePath(string fileName)
+        {
+            if (string.IsNullOrEmpty(fileName)) return fileName;
+
+            int i;
+
+            bool isWeb = false;
+            for (i = 0; i < fileName.Length; i++)
+            {
+                if (fileName[i] == '/' || fileName[i] == '\\')
+                    break;
+                if (fileName[i] == ':')
+                {
+                    if (i > 1)
+                        isWeb = true;
+                    break;
+                }
+            }
+
+            char outputSeparator = isWeb ? '/' : System.IO.Path.DirectorySeparatorChar;
+
+            StringBuilder result = new StringBuilder();
+            if (isWeb == false && fileName.StartsWith(@"\\") || fileName.StartsWith("//"))
+            {
+                i = 2;
+                result.Append(outputSeparator);
+            }
+            else
+            {
+                i = 0;
+            }
+            int segmentStartPos = i;
+            for (; i <= fileName.Length; i++)
+            {
+                if (i == fileName.Length || fileName[i] == '/' || fileName[i] == '\\')
+                {
+                    int segmentLength = i - segmentStartPos;
+                    switch (segmentLength)
+                    {
+                        case 0:
+                            // ignore empty segment (if not in web mode)
+                            // On unix, don't ignore empty segment if i==0
+                            if (isWeb || (i == 0 && Environment.OSVersion.Platform == PlatformID.Unix))
+                            {
+                                result.Append(outputSeparator);
+                            }
+                            break;
+                        case 1:
+                            // ignore /./ segment, but append other one-letter segments
+                            if (fileName[segmentStartPos] != '.')
+                            {
+                                if (result.Length > 0) result.Append(outputSeparator);
+                                result.Append(fileName[segmentStartPos]);
+                            }
+                            break;
+                        case 2:
+                            if (fileName[segmentStartPos] == '.' && fileName[segmentStartPos + 1] == '.')
+                            {
+                                // remove previous segment
+                                int j;
+                                for (j = result.Length - 1; j >= 0 && result[j] != outputSeparator; j--) ;
+                                if (j > 0)
+                                {
+                                    result.Length = j;
+                                }
+                                break;
+                            }
+                            else
+                            {
+                                // append normal segment
+                                goto default;
+                            }
+                        default:
+                            if (result.Length > 0) result.Append(outputSeparator);
+                            result.Append(fileName, segmentStartPos, segmentLength);
+                            break;
+                    }
+                    segmentStartPos = i + 1; // remember start position for next segment
+                }
+            }
+            if (isWeb == false)
+            {
+                if (result.Length > 0 && result[result.Length - 1] == outputSeparator)
+                {
+                    result.Length -= 1;
+                }
+                if (result.Length == 2 && result[1] == ':')
+                {
+                    result.Append(outputSeparator);
+                }
+            }
+            return result.ToString();
+        }
+
+        private bool IsEqualFileName(string fileName1, string fileName2)
+        {
+            return string.Equals(NormalizePath(fileName1),
+                                 NormalizePath(fileName2),
+                                 StringComparison.OrdinalIgnoreCase);
+        }
+
+        /// <summary>
+        ///   Enumerator that can iterate through a XmlSchemaCompletionDataCollection.
+        /// </summary>
+        /// <seealso cref='IEnumerator'/>
+        /// <seealso cref='XmlSchemaCompletionDataCollection'/>
+        /// <seealso cref='XmlSchemaCompletionData'/>
+        public class XmlSchemaCompletionDataEnumerator : System.Collections.IEnumerator
+        {
+            System.Collections.IEnumerator baseEnumerator;
+            System.Collections.IEnumerable temp;
+
+            /// <summary>
+            ///   Initializes a new instance of <see cref='XmlSchemaCompletionDataEnumerator'/>.
+            /// </summary>
+            public XmlSchemaCompletionDataEnumerator(XmlSchemaCompletionDataCollection mappings)
+            {
+                this.temp = ((System.Collections.IEnumerable)(mappings));
+                this.baseEnumerator = temp.GetEnumerator();
+            }
+
+            /// <summary>
+            ///   Gets the current <see cref='XmlSchemaCompletionData'/> in the <seealso cref='XmlSchemaCompletionDataCollection'/>.
+            /// </summary>
+            public XmlSchemaCompletionData Current
+            {
+                get
+                {
+                    return ((XmlSchemaCompletionData)(baseEnumerator.Current));
+                }
+            }
+
+            object System.Collections.IEnumerator.Current
+            {
+                get
+                {
+                    return baseEnumerator.Current;
+                }
+            }
+
+            /// <summary>
+            ///   Advances the enumerator to the next <see cref='XmlSchemaCompletionData'/> of the <see cref='XmlSchemaCompletionDataCollection'/>.
+            /// </summary>
+            public bool MoveNext()
+            {
+                return baseEnumerator.MoveNext();
+            }
+
+            /// <summary>
+            ///   Sets the enumerator to its initial position, which is before the first element in the <see cref='XmlSchemaCompletionDataCollection'/>.
+            /// </summary>
+            public void Reset()
+            {
+                baseEnumerator.Reset();
+            }
+        }
+
+        XmlSchemaCompletionData GetItem(string namespaceUri)
+        {
+            XmlSchemaCompletionData matchedItem = null;
+
+            foreach (XmlSchemaCompletionData item in this)
+            {
+                if (item.NamespaceUri == namespaceUri)
+                {
+                    matchedItem = item;
+                    break;
+                }
+            }
+
+            return matchedItem;
+        }
+    }
+}

Added: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaManager.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaManager.cs	                        (rev 0)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditor/AutoCompletion/XmlSchemaManager.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -0,0 +1,321 @@
+#region Disclaimer / License
+// Copyright (C) 2013, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
+// Copyright 2002-2010 by
+//
+//  AlphaSierraPapa, Christoph Wille
+//  Vordernberger Strasse 27/8
+//  A-8700 Leoben
+//  Austria
+//
+//  email: office at alphasierrapapa.com
+//  court of jurisdiction: Landesgericht Leoben
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
+{
+    /// <summary>
+    /// Keeps track of all the schemas that the Xml Editor is aware
+    /// of.
+    /// </summary>
+    public class XmlSchemaManager
+    {
+        public const string XmlSchemaNamespace = "http://www.w3.org/2001/XMLSchema";
+
+        static XmlSchemaCompletionDataCollection schemas = null;
+        static XmlSchemaManager manager = null;
+
+        public static event EventHandler UserSchemaAdded;
+
+        public static event EventHandler UserSchemaRemoved;
+
+        XmlSchemaManager()
+        {
+        }
+
+        /// <summary>
+        /// Determines whether the specified namespace is actually the W3C namespace for
+        /// XSD files.
+        /// </summary>
+        public static bool IsXmlSchemaNamespace(string schemaNamespace)
+        {
+            return schemaNamespace == XmlSchemaNamespace;
+        }
+
+        public static XmlSchemaManager Instance
+        {
+            get
+            {
+                if (manager == null)
+                    manager = new XmlSchemaManager();
+
+                if (schemas == null)
+                    schemas = new XmlSchemaCompletionDataCollection();
+
+                return manager;
+            }
+        }
+
+        /// <summary>
+        /// Gets the schemas that SharpDevelop knows about.
+        /// </summary>
+        public XmlSchemaCompletionDataCollection SchemaCompletionDataItems
+        {
+            get
+            {
+                return schemas;
+            }
+        }
+
+        /// <summary>
+        /// Gets the schema completion data that is associated with the
+        /// specified file extension.
+        /// </summary>
+        public XmlSchemaCompletionData GetSchemaCompletionData(string extension)
+        {
+            XmlSchemaCompletionData data = null;
+
+            XmlSchemaAssociation association = GetSchemaAssociation(extension);
+            if (association != null)
+            {
+                if (association.NamespaceUri.Length > 0)
+                {
+                    data = SchemaCompletionDataItems[association.NamespaceUri];
+                }
+            }
+            return data;
+        }
+
+        /// <summary>
+        /// Gets the namespace prefix that is associated with the
+        /// specified file extension.
+        /// </summary>
+        public static string GetNamespacePrefix(string extension)
+        {
+            string prefix = String.Empty;
+
+            XmlSchemaAssociation association = GetSchemaAssociation(extension);
+            if (association != null)
+            {
+                prefix = association.NamespacePrefix;
+            }
+
+            return prefix;
+        }
+
+        /// <summary>
+        /// Gets an association between a schema and a file extension.
+        /// </summary>
+        /// <remarks>
+        /// <para>The property will be an xml element when the SharpDevelopProperties.xml
+        /// is read on startup.  The property will be a schema association
+        /// if the user changes the schema associated with the file
+        /// extension in tools->options.</para>
+        /// <para>The normal way of doing things is to
+        /// pass the GetProperty method a default value which auto-magically
+        /// turns the xml element into a schema association so we would not 
+        /// have to check for both.  In this case, however, I do not want
+        /// a default saved to the SharpDevelopProperties.xml file unless the user
+        /// makes a change using Tools->Options.</para>
+        /// <para>If we have a file extension that is currently missing a default 
+        /// schema then if we  ship the schema at a later date the association will 
+        /// be updated by the code if the user has not changed the settings themselves. 
+        /// </para>
+        /// <para>For example, the initial release of the xml editor add-in had
+        /// no default schema for .xsl files, by default it was associated with
+        /// no schema and this setting is saved if the user ever viewed the settings
+        /// in the tools->options dialog.  Now, after the initial release the
+        /// .xsl schema was created and shipped with SharpDevelop, there is
+        /// no way to associate this schema to .xsl files by default since 
+        /// the property exists in the SharpDevelopProperties.xml file.</para>
+        /// <para>An alternative way of doing this might be to have the
+        /// config info in the schema itself, which a special SharpDevelop 
+        /// namespace.  I believe this is what Visual Studio does.  This
+        /// way is not as flexible since it requires the user to locate
+        /// the schema and change the association manually.</para>
+        /// </remarks>
+        static XmlSchemaAssociation GetSchemaAssociation(string extension)
+        {
+            extension = extension.ToLower();
+            return XmlSchemaAssociation.GetDefaultAssociation(extension);
+        }
+
+        /// <summary>
+        /// Removes the schema with the specified namespace from the
+        /// user schemas folder and removes the completion data.
+        /// </summary>
+        public void RemoveUserSchema(string namespaceUri)
+        {
+            XmlSchemaCompletionData schemaData = SchemaCompletionDataItems[namespaceUri];
+            if (schemaData != null)
+            {
+                if (File.Exists(schemaData.FileName))
+                {
+                    File.Delete(schemaData.FileName);
+                }
+                SchemaCompletionDataItems.Remove(schemaData);
+                OnUserSchemaRemoved();
+            }
+        }
+
+        /*
+        /// <summary>
+        /// Adds the schema to the user schemas folder and makes the
+        /// schema available to the xml editor.
+        /// </summary>
+        public static void AddUserSchema(XmlSchemaCompletionData schemaData)
+        {
+            if (SchemaCompletionDataItems[schemaData.NamespaceUri] == null)
+            {
+
+                if (!Directory.Exists(UserSchemaFolder))
+                {
+                    Directory.CreateDirectory(UserSchemaFolder);
+                }
+
+                string fileName = Path.GetFileName(schemaData.FileName);
+                string destinationFileName = Path.Combine(UserSchemaFolder, fileName);
+                File.Copy(schemaData.FileName, destinationFileName);
+                schemaData.FileName = destinationFileName;
+                SchemaCompletionDataItems.Add(schemaData);
+                OnUserSchemaAdded();
+            }
+            else
+            {
+                Debug.WriteLine("Trying to add a schema that already exists.  Namespace=" + schemaData.NamespaceUri);
+            }
+        }
+        
+        /// <summary>
+        /// Reads the system and user added schemas.
+        /// </summary>
+        void ReadSchemas()
+        {
+            // MSBuild schemas are in framework directory:
+            ReadSchemas(RuntimeEnvironment.GetRuntimeDirectory(), true);
+            ReadSchemas(SchemaFolder, true);
+            ReadSchemas(UserSchemaFolder, false);
+        }
+         */
+
+        /// <summary>
+        /// Reads all .xsd files in the specified folder.
+        /// </summary>
+        public void ReadSchemas(string folder, bool readOnly)
+        {
+            if (Directory.Exists(folder))
+            {
+                foreach (string fileName in Directory.GetFiles(folder, "*.xsd"))
+                {
+                    ReadSchema(fileName, readOnly);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Reads an individual schema and adds it to the collection.
+        /// </summary>
+        /// <remarks>
+        /// If the schema namespace exists in the collection it is not added.
+        /// </remarks>
+        public void ReadSchema(string fileName, bool readOnly)
+        {
+            try
+            {
+                string baseUri = XmlSchemaCompletionData.GetUri(fileName);
+                XmlSchemaCompletionData data = new XmlSchemaCompletionData(baseUri, fileName);
+                if (data.NamespaceUri != null)
+                {
+                    if (schemas[data.NamespaceUri] == null)
+                    {
+                        data.ReadOnly = readOnly;
+                        schemas.Add(data);
+                    }
+                    else
+                    {
+                        // Namespace already exists.
+                        Debug.WriteLine("Ignoring duplicate schema namespace " + data.NamespaceUri);
+                    }
+                }
+                else
+                {
+                    Debug.WriteLine("Ignoring schema with no namespace " + data.FileName);
+                }
+            }
+            catch (Exception ex)
+            {
+                Debug.WriteLine("Unable to read schema '" + fileName + "'. ", ex);
+            }
+        }
+
+        /*
+        /// <summary>
+        /// Gets the folder where the schemas for all users on the
+        /// local machine are stored.
+        /// </summary>
+        static string SchemaFolder
+        {
+            get
+            {
+                return Path.Combine(PropertyService.DataDirectory, "schemas");
+            }
+        }
+
+        /// <summary>
+        /// Gets the folder where schemas are stored for an individual user.
+        /// </summary>
+        static string UserSchemaFolder
+        {
+            get
+            {
+                return Path.Combine(PropertyService.ConfigDirectory, "schemas");
+            }
+        }
+        */
+
+        /// <summary>
+        /// Should really pass schema info with the event.
+        /// </summary>
+        static void OnUserSchemaAdded()
+        {
+            if (UserSchemaAdded != null)
+            {
+                UserSchemaAdded(manager, new EventArgs());
+            }
+        }
+
+        /// <summary>
+        /// Should really pass schema info with the event.
+        /// </summary>
+        static void OnUserSchemaRemoved()
+        {
+            if (UserSchemaRemoved != null)
+            {
+                UserSchemaRemoved(manager, new EventArgs());
+            }
+        }
+    }
+}

Modified: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditorCtrl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditorCtrl.cs	2013-09-06 17:36:14 UTC (rev 7849)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlEditorCtrl.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -97,6 +97,12 @@
 
             txtXmlContent.TextChanged += new EventHandler(OnTextContentChanged);
         }
+
+        public void LoadAutoCompletionData(string xsdPath)
+        {
+            txtXmlContent.SchemaCompletionDataItems = Maestro.Editors.Generic.XmlEditor.AutoCompletion.XmlSchemaManager.Instance.SchemaCompletionDataItems;
+            txtXmlContent.DefaultSchemaCompletionData = new XmlEditor.AutoCompletion.XmlSchemaCompletionData(xsdPath);
+        }
         
         private string _origText;
         

Modified: trunk/Tools/Maestro/Maestro.Editors/Generic/XmlTextEditorControl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Generic/XmlTextEditorControl.cs	2013-09-06 17:36:14 UTC (rev 7849)
+++ trunk/Tools/Maestro/Maestro.Editors/Generic/XmlTextEditorControl.cs	2013-09-06 17:39:32 UTC (rev 7850)
@@ -30,6 +30,7 @@
 using ICSharpCode.TextEditor.Gui.CompletionWindow;
 using Maestro.Editors.Generic.XmlEditor;
 using System.Drawing;
+using Maestro.Editors.Generic.XmlEditor.AutoCompletion;
 
 namespace Maestro.Editors.Generic
 {
@@ -83,6 +84,275 @@
             else
                 action();
         }
+
+        #region XML auto-completion stuff
+
+        protected override void InitializeTextAreaControl(TextAreaControl newControl)
+        {
+            base.InitializeTextAreaControl(newControl);
+
+            //primaryTextAreaControl = newControl;
+
+            newControl.TextArea.KeyEventHandler += new ICSharpCode.TextEditor.KeyEventHandler(HandleKeyPress);
+            /*
+            newControl.ContextMenuStrip = contextMenuStrip;
+            newControl.SelectionManager.SelectionChanged += new EventHandler(SelectionChanged);
+            newControl.Document.DocumentChanged += new DocumentEventHandler(DocumentChanged);
+            newControl.TextArea.ClipboardHandler.CopyText += new CopyTextEventHandler(ClipboardHandlerCopyText);
+
+            newControl.MouseWheel += new MouseEventHandler(TextAreaMouseWheel);
+            newControl.DoHandleMousewheel = false;
+             */
+        }
+
+        CodeCompletionWindow codeCompletionWindow;
+        XmlSchemaCompletionDataCollection schemaCompletionDataItems = new XmlSchemaCompletionDataCollection();
+        XmlSchemaCompletionData defaultSchemaCompletionData = null;
+
+        /// <summary>
+        /// Gets the schemas that the xml editor will use.
+        /// </summary>
+        /// <remarks>
+        /// Probably should NOT have a 'set' property, but allowing one
+        /// allows us to share the completion data amongst multiple
+        /// xml editor controls.
+        /// </remarks>
+        public XmlSchemaCompletionDataCollection SchemaCompletionDataItems
+        {
+            get
+            {
+                return schemaCompletionDataItems;
+            }
+            set
+            {
+                schemaCompletionDataItems = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the default schema completion data associated with this
+        /// view.
+        /// </summary>
+        public XmlSchemaCompletionData DefaultSchemaCompletionData
+        {
+            get
+            {
+                return defaultSchemaCompletionData;
+            }
+            set
+            {
+                defaultSchemaCompletionData = value;
+            }
+        }
+
+        char GetCharacterBeforeCaret()
+        {
+            string text = Document.GetText(ActiveTextAreaControl.TextArea.Caret.Offset - 1, 1);
+            if (text.Length > 0)
+            {
+                return text[0];
+            }
+
+            return '\0';
+        }
+
+        bool IsCaretAtDocumentStart
+        {
+            get
+            {
+                return ActiveTextAreaControl.TextArea.Caret.Offset == 0;
+            }
+        }
+
+        /// <summary>
+        /// Called when the user hits Ctrl+Space.
+        /// </summary>
+        public void ShowCompletionWindow()
+        {
+            if (!IsCaretAtDocumentStart)
+            {
+                // Find character before cursor.
+
+                char ch = GetCharacterBeforeCaret();
+
+                HandleKeyPress(ch);
+            }
+        }
+
+        /// <summary>
+        /// Captures the user's key presses.
+        /// </summary>
+        /// <remarks>
+        /// <para>The code completion window ProcessKeyEvent is not perfect
+        /// when typing xml.  If enter a space or ':' the text is
+        /// autocompleted when it should not be.</para>
+        /// <para>The code completion window has one predefined width,
+        /// which cuts off any long namespaces that we show.</para>
+        /// <para>The above issues have been resolved by duplicating
+        /// the code completion window and fixing the problems in the
+        /// duplicated class.</para>
+        /// </remarks>
+        protected bool HandleKeyPress(char ch)
+        {
+            if (IsCodeCompletionWindowOpen)
+            {
+                if (codeCompletionWindow.ProcessKeyEvent(ch))
+                {
+                    return false;
+                }
+            }
+
+            try
+            {
+                switch (ch)
+                {
+                    case '<':
+                    case ' ':
+                    case '=':
+                        ShowCompletionWindow(ch);
+                        return false;
+                    default:
+                        if (XmlParser.IsAttributeValueChar(ch))
+                        {
+                            if (IsInsideQuotes(ActiveTextAreaControl.TextArea))
+                            {
+                                // Have to insert the character ourselves since
+                                // it is not actually inserted yet.  If it is not
+                                // inserted now the code completion will not work
+                                // since the completion data provider attempts to
+                                // include the key typed as the pre-selected text.
+                                InsertCharacter(ch);
+                                ShowCompletionWindow(ch);
+                                return true;
+                            }
+                        }
+                        break;
+                }
+            }
+            catch (Exception e)
+            {
+                ErrorDialog.Show(e);
+            }
+
+            return false;
+        }
+
+        bool IsCodeCompletionEnabled
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Checks whether the caret is inside a set of quotes (" or ').
+        /// </summary>
+        bool IsInsideQuotes(TextArea textArea)
+        {
+            bool inside = false;
+
+            LineSegment line = textArea.Document.GetLineSegment(textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset));
+            if (line != null)
+            {
+                if ((line.Offset + line.Length > textArea.Caret.Offset) &&
+                    (line.Offset < textArea.Caret.Offset))
+                {
+
+                    char charAfter = textArea.Document.GetCharAt(textArea.Caret.Offset);
+                    char charBefore = textArea.Document.GetCharAt(textArea.Caret.Offset - 1);
+
+                    if (((charBefore == '\'') && (charAfter == '\'')) ||
+                        ((charBefore == '\"') && (charAfter == '\"')))
+                    {
+                        inside = true;
+                    }
+                }
+            }
+
+            return inside;
+        }
+
+        /// <summary>
+        /// Inserts a character into the text editor at the current offset.
+        /// </summary>
+        /// <remarks>
+        /// This code is copied from the TextArea.SimulateKeyPress method.  This
+        /// code is needed to handle an issue with code completion.  What if
+        /// we want to include the character just typed as the pre-selected text
+        /// for autocompletion?  If we do not insert the character before
+        /// displaying the autocompletion list we cannot set the pre-selected text
+        /// because it is not actually inserted yet.  The autocompletion window
+        /// checks the offset of the pre-selected text and closes the window
+        /// if the range is wrong.  The offset check is always wrong since the text
+        /// does not actually exist yet.  The check occurs in
+        /// CodeCompletionWindow.CaretOffsetChanged:
+        /// <code>[[!CDATA[	int offset = control.ActiveTextAreaControl.Caret.Offset;
+        ///
+        ///	if (offset < startOffset || offset > endOffset) {
+        ///		Close();
+        ///	} else {
+        ///		codeCompletionListView.SelectItemWithStart(control.Document.GetText(startOffset, offset - startOffset));
+        ///	}]]
+        /// </code>
+        /// The Close method is called because the offset is out of the range.
+        /// </remarks>
+        void InsertCharacter(char ch)
+        {
+            ActiveTextAreaControl.TextArea.BeginUpdate();
+            Document.UndoStack.StartUndoGroup();
+
+            switch (ActiveTextAreaControl.TextArea.Caret.CaretMode)
+            {
+                case CaretMode.InsertMode:
+                    ActiveTextAreaControl.TextArea.InsertChar(ch);
+                    break;
+                case CaretMode.OverwriteMode:
+                    ActiveTextAreaControl.TextArea.ReplaceChar(ch);
+                    break;
+            }
+            int currentLineNr = ActiveTextAreaControl.TextArea.Caret.Line;
+            Document.FormattingStrategy.FormatLine(ActiveTextAreaControl.TextArea, currentLineNr, Document.PositionToOffset(ActiveTextAreaControl.TextArea.Caret.Position), ch);
+
+            ActiveTextAreaControl.TextArea.EndUpdate();
+            Document.UndoStack.EndUndoGroup();
+        }
+
+        void CodeCompletionWindowClosed(object sender, EventArgs e)
+        {
+            codeCompletionWindow.Closed -= new EventHandler(CodeCompletionWindowClosed);
+            codeCompletionWindow.Dispose();
+            codeCompletionWindow = null;
+        }
+
+        bool IsCodeCompletionWindowOpen
+        {
+            get
+            {
+                return ((codeCompletionWindow != null) && (!codeCompletionWindow.IsDisposed));
+            }
+        }
+
+        void ShowCompletionWindow(char ch)
+        {
+            if (IsCodeCompletionWindowOpen)
+            {
+                codeCompletionWindow.Close();
+            }
+
+            if (IsCodeCompletionEnabled)
+            {
+                XmlCompletionDataProvider completionDataProvider = new XmlCompletionDataProvider(schemaCompletionDataItems, defaultSchemaCompletionData, string.Empty /* defaultNamespacePrefix */);
+                codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(ParentForm, this, FileName, completionDataProvider, ch, true /* showDeclarationWindow */, false);
+
+                if (codeCompletionWindow != null)
+                {
+                    codeCompletionWindow.Closed += new EventHandler(CodeCompletionWindowClosed);
+                }
+            }
+        }
+
+        #endregion
     }
 
     public class TextEditorProperties : ITextEditorProperties
@@ -286,6 +556,7 @@
                 ShowInvalidLines = true,
                 ShowMatchingBracket = true,
                 IsIconBarVisible = true,
+                IndentStyle = ICSharpCode.TextEditor.Document.IndentStyle.Smart,
                 IndentationSize = 2,
                 DocumentSelectionMode = ICSharpCode.TextEditor.Document.DocumentSelectionMode.Normal,
                 LineViewerStyle = ICSharpCode.TextEditor.Document.LineViewerStyle.FullRow,

Modified: trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj	2013-09-06 17:36:14 UTC (rev 7849)
+++ trunk/Tools/Maestro/Maestro.Editors/Maestro.Editors.csproj	2013-09-06 17:39:32 UTC (rev 7850)
@@ -545,6 +545,17 @@
     <Compile Include="Fusion\WidgetSettingsCtrl.Designer.cs">
       <DependentUpon>WidgetSettingsCtrl.cs</DependentUpon>
     </Compile>
+    <Compile Include="Generic\XmlEditor\AutoCompletion\QualifiedName.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\QualifiedNameCollection.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlCompletionData.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlCompletionDataCollection.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlCompletionDataProvider.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlElementPath.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlParser.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlSchemaAssociation.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlSchemaCompletionData.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlSchemaCompletionDataCollection.cs" />
+    <Compile Include="Generic\XmlEditor\AutoCompletion\XmlSchemaManager.cs" />
     <Compile Include="Generic\XmlEditor\XmlEditorOptions.cs" />
     <Compile Include="Generic\XmlEditor\XmlFoldingStrategy.cs" />
     <Compile Include="Generic\XmlEditor\XmlFormattingStrategy.cs" />



More information about the mapguide-commits mailing list