Commit 3e051754 authored by Tebjan Halm's avatar Tebjan Halm
Browse files

added a possibility to let the IdManager fix duplicated and wrong formated element ids

parent c251882d
...@@ -11,4 +11,28 @@ namespace Svg ...@@ -11,4 +11,28 @@ namespace Svg
{ {
} }
} }
public class SvgIDException : FormatException
{
public SvgIDException(string message)
: base(message)
{
}
}
public class SvgIDExistsException : SvgIDException
{
public SvgIDExistsException(string message)
: base(message)
{
}
}
public class SvgIDWrongFormatException : SvgIDException
{
public SvgIDWrongFormatException(string message)
: base(message)
{
}
}
} }
\ No newline at end of file
...@@ -259,26 +259,40 @@ namespace Svg ...@@ -259,26 +259,40 @@ namespace Svg
get { return this.Attributes.GetAttribute<string>("ID"); } get { return this.Attributes.GetAttribute<string>("ID"); }
set set
{ {
// Don't do anything if it hasn't changed SetAndFixID(value, false);
if (string.Compare(this.ID, value) == 0) }
{ }
return;
}
if (this.OwnerDocument != null) public void SetAndFixID(string value, bool autoFixID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
{ {
this.OwnerDocument.IdManager.Remove(this); // Don't do anything if it hasn't changed
} if (string.Compare(this.ID, value) == 0)
{
return;
}
this.Attributes["ID"] = value; if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Remove(this);
}
if (this.OwnerDocument != null) this.Attributes["ID"] = value;
{
this.OwnerDocument.IdManager.Add(this); if (this.OwnerDocument != null)
} {
this.OwnerDocument.IdManager.AddAndFixID(this, autoFixID, logElementOldIDNewID);
} }
} }
/// <summary>
/// Only used by the ID Manager
/// </summary>
/// <param name="newID"></param>
internal void FixID(string newID)
{
this.Attributes["ID"] = newID;
}
/// <summary> /// <summary>
/// Called by the underlying <see cref="SvgElement"/> when an element has been added to the /// Called by the underlying <see cref="SvgElement"/> when an element has been added to the
/// <see cref="Children"/> collection. /// <see cref="Children"/> collection.
......
...@@ -73,12 +73,21 @@ namespace Svg ...@@ -73,12 +73,21 @@ namespace Svg
} }
public void Add(SvgElement item) public void Add(SvgElement item)
{
this.AddAndFixID(item, false, false);
}
public void AddAndFixID(SvgElement item, bool autoFixID = true, bool autoFixChildrenID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
{ {
if (!this._mock) if (!this._mock)
{ {
if (this._owner.OwnerDocument != null) if (this._owner.OwnerDocument != null)
{ {
item.ApplyRecursive(this._owner.OwnerDocument.IdManager.Add); this._owner.OwnerDocument.IdManager.AddAndFixID(item, autoFixID, logElementOldIDNewID);
foreach (var child in item.Children)
{
child.ApplyRecursive(e => this._owner.OwnerDocument.IdManager.AddAndFixID(e, autoFixChildrenID, logElementOldIDNewID));
}
} }
item._parent = this._owner; item._parent = this._owner;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
namespace Svg namespace Svg
{ {
...@@ -47,13 +48,35 @@ namespace Svg ...@@ -47,13 +48,35 @@ namespace Svg
/// <param name="element">The <see cref="SvgElement"/> to be managed.</param> /// <param name="element">The <see cref="SvgElement"/> to be managed.</param>
public virtual void Add(SvgElement element) public virtual void Add(SvgElement element)
{ {
AddAndFixID(element, 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="autoFixID">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 AddAndFixID(SvgElement element, bool autoFixID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
{
var result = false;
if (!string.IsNullOrEmpty(element.ID)) if (!string.IsNullOrEmpty(element.ID))
{ {
this.EnsureValidId(element.ID); var newID = this.EnsureValidId(element.ID, autoFixID);
if (autoFixID && newID != element.ID)
{
if(logElementOldIDNewID != null)
logElementOldIDNewID(element, element.ID, newID);
element.FixID(newID);
result = true;
}
this._idValueMap.Add(element.ID, element); this._idValueMap.Add(element.ID, element);
} }
OnAdded(element); OnAdded(element);
return result;
} }
/// <summary> /// <summary>
...@@ -78,23 +101,47 @@ namespace Svg ...@@ -78,23 +101,47 @@ namespace Svg
/// <para>The ID cannot start with a digit.</para> /// <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> /// <para>An element with the same ID already exists within the containing <see cref="SvgDocument"/>.</para>
/// </exception> /// </exception>
public void EnsureValidId(string id) public string EnsureValidId(string id, bool autoFixID = false)
{ {
if (string.IsNullOrEmpty(id)) if (string.IsNullOrEmpty(id))
{ {
return; return id;
} }
if (char.IsDigit(id[0])) if (char.IsDigit(id[0]))
{ {
throw new SvgException("ID cannot start with a digit: '" + id + "'."); if (autoFixID)
{
return EnsureValidId("id" + id, true);
}
throw new SvgIDWrongFormatException("ID cannot start with a digit: '" + id + "'.");
} }
if (this._idValueMap.ContainsKey(id)) if (this._idValueMap.ContainsKey(id))
{ {
throw new SvgException("An element with the same ID already exists: '" + id + "'."); if(autoFixID)
{
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> /// <summary>
/// Initialises a new instance of an <see cref="SvgElementIdManager"/>. /// Initialises a new instance of an <see cref="SvgElementIdManager"/>.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment