Skip to content

Commit 28cdae5

Browse files
committed
Added comparison icons
Moved Filter comparison setting to the viewmodel Created Attribute.ValueComparer
1 parent 7b63a45 commit 28cdae5

17 files changed

+203
-63
lines changed

Attributes.cs

+62
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,68 @@ void NotifyPropertyChanged(string info)
121121
PropertyChanged(this, new PropertyChangedEventArgs(info));
122122
}
123123
#endregion
124+
125+
public class ValueComparer : IEqualityComparer, IEqualityComparer<Attribute>
126+
{
127+
/// <summary>
128+
/// Gets a default Attribute Value equality comparer.
129+
/// </summary>
130+
public static ValueComparer Default
131+
{
132+
get
133+
{
134+
if (_Default == null)
135+
_Default = new ValueComparer();
136+
return _Default;
137+
}
138+
}
139+
static ValueComparer _Default;
140+
141+
public bool Equals(Attribute x, Attribute y)
142+
{
143+
var type_x = x.Value == null ? null : x.Value.GetType();
144+
var type_y = y.Value == null ? null : y.Value.GetType();
145+
146+
if (type_x == null && type_y == null)
147+
return true;
148+
149+
if (type_x != type_y)
150+
return false;
151+
152+
var inner = Datamodel.GetArrayInnerType(type_x);
153+
if (inner != null)
154+
{
155+
var array_left = (IList)x.Value;
156+
var array_right = (IList)y.Value;
157+
158+
if (array_left.Count != array_right.Count) return false;
159+
160+
var comparer = inner == typeof(Element) ? (IEqualityComparer)Element.IDComparer.Default : EqualityComparer<object>.Default;
161+
162+
return !Enumerable.Range(0, array_left.Count).Any(i => !comparer.Equals(array_left[i], array_right[i]));
163+
}
164+
else if (type_x == typeof(Element))
165+
return Element.IDComparer.Default.Equals((Element)x.Value, (Element)y.Value);
166+
else
167+
return EqualityComparer<object>.Default.Equals(x.Value, y.Value);
168+
}
169+
170+
public int GetHashCode(Attribute obj)
171+
{
172+
return obj.Value.GetHashCode();
173+
}
174+
175+
bool IEqualityComparer.Equals(object x, object y)
176+
{
177+
return Equals((Attribute)x, (Attribute)y);
178+
}
179+
180+
int IEqualityComparer.GetHashCode(object obj)
181+
{
182+
return GetHashCode((Attribute)obj);
183+
}
184+
}
185+
124186
}
125187

126188
public abstract class VectorBase : IEnumerable<float>, INotifyPropertyChanged

Datamodel.cs

+21-9
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public CodecRegistration(string encoding, int version)
7878
}
7979
static Dictionary<CodecRegistration, Type> Codecs = new Dictionary<CodecRegistration, Type>();
8080

81-
public static IEnumerable<Codec_t> CodecsRegistered { get { return Codecs.Select(t => new Codec_t(t.Key.Encoding,t.Key.Version)); } }
81+
public static IEnumerable<Codec_t> CodecsRegistered { get { return Codecs.Select(t => new Codec_t(t.Key.Encoding, t.Key.Version)); } }
8282

8383
/// <summary>
8484
/// Registers a new <see cref="ICodec"/> with an encoding name and one or more encoding versions.
@@ -195,7 +195,7 @@ static Datamodel Load_Internal(Stream stream, DeferredMode defer_mode = Deferred
195195
var match = System.Text.RegularExpressions.Regex.Match(header, CodecUtilities.HeaderPattern_Regex);
196196

197197
if (!match.Success || match.Groups.Count != 5)
198-
throw new InvalidOperationException(String.Format("Could not read DMX header ({0}).",header));
198+
throw new InvalidOperationException(String.Format("Could not read DMX header ({0}).", header));
199199

200200
string encoding = match.Groups[1].Value;
201201
int encoding_version = int.Parse(match.Groups[2].Value);
@@ -217,7 +217,7 @@ static Datamodel Load_Internal(Stream stream, DeferredMode defer_mode = Deferred
217217

218218
dm.Encoding = encoding;
219219
dm.EncodingVersion = encoding_version;
220-
220+
221221
return dm;
222222
}
223223

@@ -348,6 +348,14 @@ public void Dispose()
348348
}
349349

350350
#region Properties
351+
352+
public bool AllowRandomIDs
353+
{
354+
get { return _AllowRandomIDs; }
355+
set { _AllowRandomIDs = value; NotifyPropertyChanged("AllowRandomIDs"); }
356+
}
357+
bool _AllowRandomIDs = true;
358+
351359
/// <summary>
352360
/// Gets or sets a <see cref="FileInfo"/> object associated with this Datamodel.
353361
/// </summary>
@@ -524,10 +532,13 @@ public Element CreateStubElement(Guid id)
524532
/// Creates a new Element with a random ID.
525533
/// </summary>
526534
/// <param name="name">The Element's name. Duplicates allowed.</param>
527-
/// <param name="id">The Element's ID. Must be unique within the Datamodel.</param>
535+
/// <param name="class_name">The Element's class.</param>
528536
/// <returns>The new Element.</returns>
529537
public Element CreateElement(string name, string class_name = "DmElement")
530538
{
539+
if (!AllowRandomIDs)
540+
throw new InvalidOperationException("Random IDs are not allowed in this Datamodel.");
541+
531542
Guid id;
532543
do { id = Guid.NewGuid(); }
533544
while (AllElements[id] != null);
@@ -539,7 +550,7 @@ public Element CreateElement(string name, string class_name = "DmElement")
539550
/// </summary>
540551
/// <param name="name">The Element's name. Duplicates allowed.</param>
541552
/// <param name="id">The Element's ID. Must be unique within the Datamodel.</param>
542-
/// <param name="class_name">the Element's class.</param>
553+
/// <param name="class_name">The Element's class.</param>
543554
/// <returns>The new Element.</returns>
544555
public Element CreateElement(string name, Guid id, string class_name = "DmElement")
545556
{
@@ -549,15 +560,16 @@ public Element CreateElement(string name, Guid id, string class_name = "DmElemen
549560
internal int ElementsAdded = 0; // used to optimise de-stubbing
550561
internal Element CreateElement(string name, Guid id, bool stub, string classname = "DmElement")
551562
{
552-
if (AllElements.Count == Int32.MaxValue) // jinkies!
553-
throw new InvalidOperationException("Maximum Element count reached.");
554-
555563
lock (AllElements.ChangeLock)
556564
{
565+
if (AllElements.Count == Int32.MaxValue) // jinkies!
566+
throw new InvalidOperationException("Maximum Element count reached.");
567+
557568
if (AllElements[id] != null)
558569
throw new ElementIdException(String.Format("Element ID {0} already in use in this Datamodel.", id.ToString()));
570+
571+
if (!stub) ElementsAdded++;
559572
}
560-
if (!stub) ElementsAdded++;
561573
return new Element(this, id, name, classname, stub);
562574
}
563575
#endregion

DmxPad/App.xaml

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<converter:AttributeGroupDisplay x:Key="AttributeDisplay"/>
1919
<converter:DatamodelPath x:Key="DatamodelPathConverter"/>
2020
<converter:ComparisonTreeVisibility x:Key="ComparisonTreeVisibility"/>
21+
<converter:ComparisonIcon x:Key="ComparisonIcon"/>
2122

2223
<l:InspectPaneTemplateSelector x:Key="InspectPaneTemplateSelector"/>
2324
<converter:ValueColumnTemplateSelector x:Key="ValueColumnTemplateSelector"/>

DmxPad/ComparisonDatamodel.cs

+23-38
Original file line numberDiff line numberDiff line change
@@ -235,55 +235,40 @@ public Attribute(Element owner, Datamodel.Attribute attr_left, Datamodel.Attribu
235235
Name = Attribute_Left != null ? Attribute_Left.Name : Attribute_Right.Name;
236236

237237
if (Attribute_Left == null)
238+
{
238239
State = ComparisonState.Added;
240+
Value_Combined = Attribute_Right.Value;
241+
}
239242
else if (Attribute_Right == null)
243+
{
240244
State = ComparisonState.Removed;
245+
Value_Combined = Attribute_Left.Value;
246+
}
241247
else
242248
{
243-
var t_left = Attribute_Left.Value == null ? null : Attribute_Left.Value.GetType();
244-
var t_right = Attribute_Right.Value == null ? null : Attribute_Right.Value.GetType();
249+
if (!Datamodel.Attribute.ValueComparer.Default.Equals(Attribute_Left, Attribute_Right))
250+
State = ComparisonState.Changed;
245251

246-
if (t_left == t_right && t_left != null)
252+
if (Attribute_Left.Value == null)
253+
Value_Combined = Attribute_Right.Value;
254+
else if (Attribute_Right.Value == null)
255+
Value_Combined = Attribute_Left.Value;
256+
else
247257
{
248-
var inner = Datamodel.Datamodel.GetArrayInnerType(t_left);
249-
250-
if (inner != null)
258+
if (Attribute_Left.Value.GetType() == typeof(Datamodel.Element))
259+
Value_Combined = new Element(cdm, (Datamodel.Element)Attribute_Left.Value, (Datamodel.Element)Attribute_Right.Value);
260+
else
251261
{
252-
var array_left = (IList)Attribute_Left.Value;
253-
var array_right = (IList)Attribute_Right.Value;
254-
if (array_left.Count != array_right.Count)
255-
State = ComparisonState.Changed;
262+
var inner = Datamodel.Datamodel.GetArrayInnerType(Attribute_Left.Value.GetType());
263+
if (inner == typeof(Datamodel.Element))
264+
Value_Combined = ((IList<Datamodel.Element>)Attribute_Left.Value)
265+
.Concat((IList<Datamodel.Element>)Attribute_Right.Value)
266+
.Distinct(Datamodel.Element.IDComparer.Default)
267+
.Select(e => new Element(cdm, cdm.Datamodel_Left.AllElements[e.ID], cdm.Datamodel_Right.AllElements[e.ID])).ToArray();
256268
else
257-
{
258-
IEqualityComparer comparer = inner == typeof(Datamodel.Element) ? (IEqualityComparer)Datamodel.Element.IDComparer.Default : EqualityComparer<object>.Default;
259-
foreach (int i in Enumerable.Range(0, array_left.Count))
260-
{
261-
if (!comparer.Equals(array_left[i], array_right[i]))
262-
{
263-
State = ComparisonState.Changed;
264-
break;
265-
}
266-
}
267-
}
269+
Value_Combined = Attribute_Right.Value;
268270
}
269-
else if (t_left == typeof(Datamodel.Element) && !Datamodel.Element.IDComparer.Default.Equals((Datamodel.Element)Attribute_Left.Value, (Datamodel.Element)Attribute_Right.Value))
270-
{
271-
State = ComparisonState.Changed;
272-
}
273-
274-
if (t_left == typeof(Datamodel.Element))
275-
Value_Combined = new Element(cdm, (Datamodel.Element)Attribute_Left.Value, (Datamodel.Element)Attribute_Right.Value);
276-
277-
else if (inner == typeof(Datamodel.Element))
278-
Value_Combined = ((IList<Datamodel.Element>)Attribute_Left.Value)
279-
.Concat((IList<Datamodel.Element>)Attribute_Right.Value)
280-
.Distinct(Datamodel.Element.IDComparer.Default)
281-
.Select(e => new Element(cdm, cdm.Datamodel_Left.AllElements[e.ID], cdm.Datamodel_Right.AllElements[e.ID])).ToArray();
282-
else
283-
Value_Combined = Attribute_Right.Value;
284271
}
285-
else
286-
State = ComparisonState.Changed;
287272
}
288273
}
289274
}

DmxPad/Converters.cs

+47-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
using DmEncoding = System.Tuple<string, int>;
1212
using Datamodel;
13+
using ComparisonState = DmxPad.ComparisonDatamodel.ComparisonState;
1314

1415
namespace DmxPad.Converters
1516
{
@@ -46,7 +47,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
4647
}
4748

4849
var celem = value as ComparisonDatamodel.Element;
49-
if (celem != null) return celem.State != ComparisonDatamodel.ComparisonState.Removed ? celem : null;
50+
if (celem != null) return celem.State != ComparisonState.Removed ? celem : null;
5051

5152
var cattr = value as ComparisonDatamodel.Attribute;
5253
if (cattr != null && cattr.Value_Combined != null)
@@ -216,7 +217,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
216217
type = type.GetGenericArguments()[0];
217218
}
218219

219-
if ( (type == typeof(Element) || type == typeof(ComparisonDatamodel.Element)) && !array)
220+
if ((type == typeof(Element) || type == typeof(ComparisonDatamodel.Element)) && !array)
220221
{
221222
var tb = new TextBlock();
222223
tb.SetBinding(TextBlock.TextProperty, new Binding()
@@ -406,14 +407,14 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur
406407

407408
var name = part;
408409
var index = -1;
409-
410+
410411
var indexer_pos = part.LastIndexOf('[');
411412
if (indexer_pos != -1)
412413
{
413414
name = part.Substring(0, indexer_pos);
414415
index = Int32.Parse(part.Substring(indexer_pos + 1, part.Length - indexer_pos - 2));
415416
}
416-
417+
417418
if (!elem.Contains(name)) return null;
418419

419420
current = attr = elem.GetAttribute(name);
@@ -444,5 +445,47 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
444445
}
445446
}
446447

448+
public class ComparisonIcon : IValueConverter
449+
{
450+
struct ComparisonStateData
451+
{
452+
public ComparisonStateData(string image, string tooltip)
453+
{
454+
ImageSource = new BitmapImage(new Uri(String.Format("/DmxPad;component/Resources/{0}.png",image), UriKind.Relative));
455+
ToolTip = tooltip;
456+
}
457+
458+
public readonly ImageSource ImageSource;
459+
public readonly string ToolTip;
460+
}
461+
static Dictionary<ComparisonState, ComparisonStateData> StateData = new Dictionary<ComparisonState, ComparisonStateData>()
462+
{
463+
{ ComparisonState.Changed, new ComparisonStateData("Changed", "This item is different") },
464+
{ ComparisonState.ChildChanged, new ComparisonStateData("ChildChanged", "One or more children of this item are different") },
465+
{ ComparisonState.Added, new ComparisonStateData("Added", "This item was added") },
466+
{ ComparisonState.Removed, new ComparisonStateData("Removed", "This item was removed") },
467+
};
468+
469+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
470+
{
471+
var state = (ComparisonState)value;
472+
473+
if (state == ComparisonState.Unchanged)
474+
return null;
475+
476+
var data = StateData[state];
477+
return new Image()
478+
{
479+
Source = data.ImageSource,
480+
ToolTip = data.ToolTip,
481+
Width = 16,
482+
Height = 16,
483+
};
484+
}
447485

486+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
487+
{
488+
throw new NotImplementedException();
489+
}
490+
}
448491
}

DmxPad/DmxPad.csproj

+19
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,25 @@
158158
<ItemGroup>
159159
<Resource Include="Resources\dmx.ico" />
160160
</ItemGroup>
161+
<ItemGroup>
162+
<Resource Include="Resources\Added.png" />
163+
<Resource Include="Resources\Removed.png" />
164+
</ItemGroup>
165+
<ItemGroup>
166+
<Resource Include="Resources\ChildChanged.png" />
167+
</ItemGroup>
168+
<ItemGroup>
169+
<Resource Include="Resources\Changed.png" />
170+
</ItemGroup>
171+
<ItemGroup>
172+
<Resource Include="readme.txt" />
173+
</ItemGroup>
174+
<ItemGroup>
175+
<Resource Include="Resources\Diff.png" />
176+
</ItemGroup>
177+
<ItemGroup>
178+
<Resource Include="Resources\Filter.png" />
179+
</ItemGroup>
161180
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
162181
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
163182
Other similar extension points exist, see Microsoft.Common.targets.

0 commit comments

Comments
 (0)