Skip to content

Commit

Permalink
Issue 42/statusbar xpath format (#43)
Browse files Browse the repository at this point in the history
* Generalized TypeConverter instantiation and handling

#42

* Fixed type converter retrieval for property type

#42

* Registry values which can't be parsed are now reset

This hopefully avoids backwards incompatabilities.

#42

* Version bumped to v6.0.2

#42
  • Loading branch information
uli-weltersbach authored Aug 12, 2019
1 parent af9bfe0 commit e1d69f7
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
[assembly: AssemblyCompany("Reason→Code→Example (http://reasoncodeexample.com)")]
[assembly: AssemblyProduct("ReasonCodeExample.XPathTools.Tests")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("6.0.1.*")]
[assembly: AssemblyVersion("6.0.2.*")]
98 changes: 76 additions & 22 deletions ReasonCodeExample.XPathTools/Configuration/XPathToolsDialogPage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
Expand All @@ -21,11 +22,11 @@ public XPathToolsDialogPage()
[Category("Statusbar")]
[DisplayName("Statusbar XPath format")]
[Description("Select the XPath format used in the statusbar.")]
public XPathFormat? StatusbarXPathFormatSetting
public XPathFormat StatusbarXPathFormatSetting
{
get;
set;
}
} = XPathFormat.Generic;

[Category("Generic XPath")]
[DisplayName("Always displayed attributes")]
Expand Down Expand Up @@ -88,35 +89,39 @@ public override void LoadSettingsFromStorage()
PreferredAttributeCandidatesSetting.ListChanged += SavePreferredAttributeCandidatesSettingToStorage;
}

#region Load and initialize settings

private void LoadCollectionsFromStorage()
{
var package = (Package)GetService(typeof(Package));
if(package == null)
{
return;
}

using(var userRegistryRoot = package.UserRegistryRoot)
{
LoadCollectionsFromRegistry(userRegistryRoot);
LoadSettingsFromRegistry(userRegistryRoot);
}
}

private void LoadCollectionsFromRegistry(RegistryKey userRegistryRoot)
private void LoadSettingsFromRegistry(RegistryKey userRegistryRoot)
{
var settingsRegistryPath = SettingsRegistryPath;
var automationObject = AutomationObject;
var registryKey = userRegistryRoot.OpenSubKey(settingsRegistryPath, false);
var registryKey = userRegistryRoot.OpenSubKey(settingsRegistryPath, true);
if(registryKey == null)
{
LoadDefaultSettings();
return;
}

using(registryKey)
{
var propertyNames = registryKey.GetValueNames();
foreach(var propertyName in propertyNames)
{
SetPropertyValue(automationObject, propertyName, registryKey);
LoadSettingValue(automationObject, propertyName, registryKey);
}
}
}
Expand All @@ -127,60 +132,109 @@ private void LoadDefaultSettings()
{
return;
}

PreferredAttributeCandidates.Add(new XPathSetting {AttributeName = "id"});
PreferredAttributeCandidates.Add(new XPathSetting {AttributeName = "name"});
PreferredAttributeCandidates.Add(new XPathSetting {AttributeName = "type"});
}

private void SetPropertyValue(object automationObject, string propertyName, RegistryKey registryKey)
private void LoadSettingValue(object automationObject, string propertyName, RegistryKey registryKey)
{
var property = automationObject.GetType().GetProperty(propertyName);
if(property == null)
{
return;
}
if(property.GetCustomAttribute(typeof(TypeConverterAttribute)) == null)

try
{
return;
var storedValue = registryKey.GetValue(propertyName).ToString();
var converter = GetTypeConverter(propertyName);
var convertedValue = converter.ConvertFrom(storedValue);
property.SetValue(automationObject, convertedValue);
}
catch(Exception e)
{
Console.Error.WriteLine(e);
// Delete the value if it can't be deserialized,
// to prevent old serialization formats from
// interfering with storing new values.
registryKey.DeleteValue(propertyName);
var defaultValue = GetDefaultValue(property);
property.SetValue(automationObject, defaultValue);
}
}

private TypeConverter GetTypeConverter(string propertyName)
{
var property = GetType().GetProperty(propertyName);
if(property == null)
{
throw new InvalidOperationException($"Property '{propertyName}' not found on type '{GetType()}.'");
}
var storedValue = registryKey.GetValue(propertyName).ToString();
var converter = new SerializableConverter<BindingList<XPathSetting>>();
property.SetValue(automationObject, converter.ConvertFrom(storedValue));

var typeConverterAttribute = property.GetCustomAttribute<TypeConverterAttribute>();
if(typeConverterAttribute == null)
{
return TypeDescriptor.GetConverter(property.PropertyType);
}

var converterType = Type.GetType(typeConverterAttribute.ConverterTypeName);
return (TypeConverter)Activator.CreateInstance(converterType);
}

private object GetDefaultValue(PropertyInfo property)
{
return property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null;
}

#endregion

#region Save settings

private void SaveAlwaysDisplayedAttributesSettingToStorage(object sender, ListChangedEventArgs e)
{
SaveCollectionToStorage(nameof(AlwaysDisplayedAttributesSetting), (BindingList<XPathSetting>)sender);
SaveSettingToStorage(nameof(AlwaysDisplayedAttributesSetting), sender);
}

private void SavePreferredAttributeCandidatesSettingToStorage(object sender, ListChangedEventArgs e)
{
SaveCollectionToStorage(nameof(PreferredAttributeCandidatesSetting), (BindingList<XPathSetting>)sender);
SaveSettingToStorage(nameof(PreferredAttributeCandidatesSetting), sender);
}

private void SaveCollectionToStorage(string propertyName, BindingList<XPathSetting> settings)
private void SaveSettingToStorage(string propertyName, object propertyValue)
{
var package = (Package)GetService(typeof(Package));
if(package == null)
{
return;
}

using(var userRegistryRoot = package.UserRegistryRoot)
{
SaveCollectionToRegistry(userRegistryRoot, propertyName, settings);
SaveSettingToRegistry(userRegistryRoot, propertyName, propertyValue);
}
}

private void SaveCollectionToRegistry(RegistryKey userRegistryRoot, string propertyName, BindingList<XPathSetting> settings)
private void SaveSettingToRegistry(RegistryKey userRegistryRoot, string propertyName, object propertyValue)
{
var settingsRegistryPath = SettingsRegistryPath;
var registryKey = userRegistryRoot.OpenSubKey(settingsRegistryPath, true) ?? userRegistryRoot.CreateSubKey(settingsRegistryPath);
using(registryKey)
{
var converter = new SerializableConverter<BindingList<XPathSetting>>();
var convertedValue = converter.ConvertTo(settings, typeof(string));
registryKey.SetValue(propertyName, convertedValue);
try
{
var converter = GetTypeConverter(propertyName);
var convertedValue = converter.ConvertTo(propertyValue, typeof(string));
registryKey.SetValue(propertyName, convertedValue);
}
catch(Exception e)
{
Console.Error.WriteLine(e);
}
}
}

#endregion
}
}
}
2 changes: 1 addition & 1 deletion ReasonCodeExample.XPathTools/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[assembly: AssemblyCompany("Reason→Code→Example (http://reasoncodeexample.com)")]
[assembly: AssemblyProduct("ReasonCodeExample.XPathTools")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("6.0.1.*")]
[assembly: AssemblyVersion("6.0.2.*")]
[assembly: InternalsVisibleTo(InternalsVisibleTo.ReasonCodeExampleXPathToolsTests)]
[assembly: InternalsVisibleTo(InternalsVisibleTo.DynamicProxyGenAssembly2)]
[assembly: InternalsVisibleTo(InternalsVisibleTo.CastleCore)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="ReasonCodeExample.XPathInformation.v1.0" Version="6.0.1" Language="en-US" Publisher="Uli Weltersbach" />
<Identity Id="ReasonCodeExample.XPathInformation.v1.0" Version="6.0.2" Language="en-US" Publisher="Uli Weltersbach" />
<DisplayName>XPath Tools</DisplayName>
<Description xml:space="preserve">Run XPaths and XPath functions. Browse through results at the click of a button.
Track and copy XPaths incl. XML namespaces in various formats, taking the hassle out of complex documents.</Description>
Expand Down
3 changes: 2 additions & 1 deletion ReasonCodeExample.XPathTools/release-notes.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
v6.0.1: XPath Runner query results now change focus to their source document when clicked. See issue #38 for details (https://github.com/uli-weltersbach/XPathTools/issues/38).
v6.0.2: The XPath format used in the statusbar is now persisted correctly. See issue #42 for details (https://github.com/uli-weltersbach/XPathTools/issues/42).
v6.0.1: XPath Runner query results now change focus to their source document when clicked. See issue #38 for details (https://github.com/uli-weltersbach/XPathTools/issues/38).
v6.0.0: Async package load implemented as required by Visual Studio 2019.1 and later. Support for Visual Studio 2013 and earlier has been dropped as a consequence.
v5.3.0: Supported Visual Studio version range updated to include VS 2019 Preview. See issue #36 for details (https://github.com/uli-weltersbach/XPathTools/issues/36).
v5.2.2: Blank text nodes are now stripped from the output of the "Copy XML structure" command. See issue #34 for details (https://github.com/uli-weltersbach/XPathTools/issues/34).
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: '6.0.1-{build}'
version: '6.0.2-{build}'
image: Visual Studio 2017
configuration: Release
platform: Any CPU
Expand Down

0 comments on commit e1d69f7

Please sign in to comment.