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
{
}
}
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
get { return this.Attributes.GetAttribute<string>("ID"); }
set
{
// Don't do anything if it hasn't changed
if (string.Compare(this.ID, value) == 0)
{
return;
}
SetAndFixID(value, false);
}
}
if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Remove(this);
}
public void SetAndFixID(string value, bool autoFixID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
{
// 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.OwnerDocument.IdManager.Add(this);
}
this.Attributes["ID"] = value;
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>
/// Called by the underlying <see cref="SvgElement"/> when an element has been added to the
/// <see cref="Children"/> collection.
......
......@@ -73,12 +73,21 @@ namespace Svg
}
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._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;
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Svg
{
......@@ -47,13 +48,35 @@ namespace Svg
/// <param name="element">The <see cref="SvgElement"/> to be managed.</param>
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))
{
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);
}
OnAdded(element);
return result;
}
/// <summary>
......@@ -78,23 +101,47 @@ namespace Svg
/// <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 void EnsureValidId(string id)
public string EnsureValidId(string id, bool autoFixID = false)
{
if (string.IsNullOrEmpty(id))
{
return;
return id;
}
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))
{
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>
/// 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