123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Net;
- using System.IO;
- #pragma warning disable
- namespace Svg
- {
- /// <summary>
- /// Provides methods to ensure element ID's are valid and unique.
- /// </summary>
- public class SvgElementIdManager
- {
- private SvgDocument _document;
- private Dictionary<string, SvgElement> _idValueMap;
- /// <summary>
- /// Retrieves the <see cref="SvgElement"/> with the specified ID.
- /// </summary>
- /// <param name="id">A <see cref="string"/> containing the ID of the element to find.</param>
- /// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns>
- public virtual SvgElement GetElementById(string id)
- {
- if (id.StartsWith("url("))
- {
- id = id.Substring(4);
- id = id.TrimEnd(')');
- }
- if (id.StartsWith("#"))
- {
- id = id.Substring(1);
- }
- SvgElement element = null;
- this._idValueMap.TryGetValue(id, out element);
- return element;
- }
- public virtual SvgElement GetElementById(Uri uri)
- {
- System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)(0xc0 | 0x300 | 0xc00);
- if (uri.ToString().StartsWith("url(")) uri = new Uri(uri.ToString().Substring(4).TrimEnd(')'), UriKind.Relative);
- if (!uri.IsAbsoluteUri && this._document.BaseUri != null && !uri.ToString().StartsWith("#"))
- {
- var fullUri = new Uri(this._document.BaseUri, uri);
- var hash = fullUri.OriginalString.Substring(fullUri.OriginalString.LastIndexOf('#'));
- SvgDocument doc;
- switch (fullUri.Scheme.ToLowerInvariant())
- {
- case "file":
- doc = SvgDocument.Open<SvgDocument>(fullUri.LocalPath.Substring(0, fullUri.LocalPath.Length - hash.Length));
- return doc.IdManager.GetElementById(hash);
- case "http":
- case "https":
- var httpRequest = WebRequest.Create(uri);
- using (WebResponse webResponse = httpRequest.GetResponse())
- {
- doc = SvgDocument.Open<SvgDocument>(webResponse.GetResponseStream());
- return doc.IdManager.GetElementById(hash);
- }
- default:
- throw new NotSupportedException();
- }
- }
- return this.GetElementById(uri.ToString());
- }
- /// <summary>
- /// Adds the specified <see cref="SvgElement"/> for ID management.
- /// </summary>
- /// <param name="element">The <see cref="SvgElement"/> to be managed.</param>
- public virtual void Add(SvgElement element)
- {
- AddAndForceUniqueID(element, null, false);
- }
- /// <summary>
- /// Adds the specified <see cref="SvgElement"/> for ID management.
- /// And can auto fix the ID if it already exists or it starts with a number.
- /// </summary>
- /// <param name="element">The <see cref="SvgElement"/> to be managed.</param>
- /// <param name="autoForceUniqueID">Pass true here, if you want the ID to be fixed</param>
- /// <param name="logElementOldIDNewID">If not null, the action is called before the id is fixed</param>
- /// <returns>true, if ID was altered</returns>
- public virtual bool AddAndForceUniqueID(SvgElement element, SvgElement sibling, bool autoForceUniqueID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
- {
- var result = false;
- if (!string.IsNullOrEmpty(element.ID))
- {
- var newID = this.EnsureValidId(element.ID, autoForceUniqueID);
- if (autoForceUniqueID && newID != element.ID)
- {
- if (logElementOldIDNewID != null)
- logElementOldIDNewID(element, element.ID, newID);
- element.ForceUniqueID(newID);
- result = true;
- }
- this._idValueMap.Add(element.ID, element);
- }
- OnAdded(element);
- return result;
- }
- /// <summary>
- /// Removed the specified <see cref="SvgElement"/> from ID management.
- /// </summary>
- /// <param name="element">The <see cref="SvgElement"/> to be removed from ID management.</param>
- public virtual void Remove(SvgElement element)
- {
- if (!string.IsNullOrEmpty(element.ID))
- {
- this._idValueMap.Remove(element.ID);
- }
- OnRemoved(element);
- }
- /// <summary>
- /// Ensures that the specified ID is valid within the containing <see cref="SvgDocument"/>.
- /// </summary>
- /// <param name="id">A <see cref="string"/> containing the ID to validate.</param>
- /// <param name="autoForceUniqueID">Creates a new unique id <see cref="string"/>.</param>
- /// <exception cref="SvgException">
- /// <para>The ID cannot start with a digit.</para>
- /// <para>An element with the same ID already exists within the containing <see cref="SvgDocument"/>.</para>
- /// </exception>
- public string EnsureValidId(string id, bool autoForceUniqueID = false)
- {
- if (string.IsNullOrEmpty(id))
- {
- return id;
- }
- if (char.IsDigit(id[0]))
- {
- if (autoForceUniqueID)
- {
- return EnsureValidId("id" + id, true);
- }
- throw new SvgIDWrongFormatException("ID cannot start with a digit: '" + id + "'.");
- }
- if (this._idValueMap.ContainsKey(id))
- {
- if (autoForceUniqueID)
- {
- var match = regex.Match(id);
- int number;
- if (match.Success && int.TryParse(match.Value.Substring(1), out number))
- {
- id = regex.Replace(id, "#" + (number + 1));
- }
- else
- {
- id += "#1";
- }
- return EnsureValidId(id, true);
- }
- throw new SvgIDExistsException("An element with the same ID already exists: '" + id + "'.");
- }
- return id;
- }
- private static readonly Regex regex = new Regex(@"#\d+$");
- /// <summary>
- /// Initialises a new instance of an <see cref="SvgElementIdManager"/>.
- /// </summary>
- /// <param name="document">The <see cref="SvgDocument"/> containing the <see cref="SvgElement"/>s to manage.</param>
- public SvgElementIdManager(SvgDocument document)
- {
- this._document = document;
- this._idValueMap = new Dictionary<string, SvgElement>();
- }
- public event EventHandler<SvgElementEventArgs> ElementAdded;
- public event EventHandler<SvgElementEventArgs> ElementRemoved;
- protected void OnAdded(SvgElement element)
- {
- var handler = ElementAdded;
- if (handler != null)
- {
- handler(this._document, new SvgElementEventArgs { Element = element });
- }
- }
- protected void OnRemoved(SvgElement element)
- {
- var handler = ElementRemoved;
- if (handler != null)
- {
- handler(this._document, new SvgElementEventArgs { Element = element });
- }
- }
- }
- public class SvgElementEventArgs : EventArgs
- {
- public SvgElement Element;
- }
- }
- #pragma warning restore
|