#region Disclaimer / License
// Copyright (C) 2013, Jackie Ng
// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@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@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 Disclaimer / License
using System;
using System.Diagnostics;
using System.IO;
namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
{
///
/// Keeps track of all the schemas that the Xml Editor is aware
/// of.
///
internal class XmlSchemaManager
{
public const string XmlSchemaNamespace = "http://www.w3.org/2001/XMLSchema";
private static XmlSchemaCompletionDataCollection schemas = null;
private static XmlSchemaManager manager = null;
public static event EventHandler UserSchemaAdded;
public static event EventHandler UserSchemaRemoved;
private XmlSchemaManager()
{
}
///
/// Determines whether the specified namespace is actually the W3C namespace for
/// XSD files.
///
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;
}
}
///
/// Gets the schemas that SharpDevelop knows about.
///
internal XmlSchemaCompletionDataCollection SchemaCompletionDataItems
{
get
{
return schemas;
}
}
///
/// Gets the schema completion data that is associated with the
/// specified file extension.
///
internal 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;
}
///
/// Gets the namespace prefix that is associated with the
/// specified file extension.
///
public static string GetNamespacePrefix(string extension)
{
string prefix = String.Empty;
XmlSchemaAssociation association = GetSchemaAssociation(extension);
if (association != null)
{
prefix = association.NamespacePrefix;
}
return prefix;
}
///
/// Gets an association between a schema and a file extension.
///
///
/// 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.
/// 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.
/// 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.
///
/// 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.
/// 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.
///
private static XmlSchemaAssociation GetSchemaAssociation(string extension)
{
extension = extension.ToLower();
return XmlSchemaAssociation.GetDefaultAssociation(extension);
}
///
/// Removes the schema with the specified namespace from the
/// user schemas folder and removes the completion data.
///
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();
}
}
/*
///
/// Adds the schema to the user schemas folder and makes the
/// schema available to the xml editor.
///
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);
}
}
///
/// Reads the system and user added schemas.
///
void ReadSchemas()
{
// MSBuild schemas are in framework directory:
ReadSchemas(RuntimeEnvironment.GetRuntimeDirectory(), true);
ReadSchemas(SchemaFolder, true);
ReadSchemas(UserSchemaFolder, false);
}
*/
///
/// Reads all .xsd files in the specified folder.
///
public void ReadSchemas(string folder, bool readOnly)
{
if (Directory.Exists(folder))
{
foreach (string fileName in Directory.GetFiles(folder, "*.xsd"))
{
ReadSchema(fileName, readOnly);
}
}
}
///
/// Reads an individual schema and adds it to the collection.
///
///
/// If the schema namespace exists in the collection it is not added.
///
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);
}
}
/*
///
/// Gets the folder where the schemas for all users on the
/// local machine are stored.
///
static string SchemaFolder
{
get
{
return Path.Combine(PropertyService.DataDirectory, "schemas");
}
}
///
/// Gets the folder where schemas are stored for an individual user.
///
static string UserSchemaFolder
{
get
{
return Path.Combine(PropertyService.ConfigDirectory, "schemas");
}
}
*/
///
/// Should really pass schema info with the event.
///
private static void OnUserSchemaAdded()
{
if (UserSchemaAdded != null)
{
UserSchemaAdded(manager, new EventArgs());
}
}
///
/// Should really pass schema info with the event.
///
private static void OnUserSchemaRemoved()
{
if (UserSchemaRemoved != null)
{
UserSchemaRemoved(manager, new EventArgs());
}
}
}
}