[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