Skip to content

Commit 9bc9d80

Browse files
committed
Add inital ReferenceSettings support.
1 parent c92d7f5 commit 9bc9d80

17 files changed

+730
-173
lines changed

Rubberduck.Core/AddRemoveReferences/ReferenceModel.cs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,35 @@ namespace Rubberduck.AddRemoveReferences
1515
public class ReferenceModel : INotifyPropertyChanged
1616
{
1717
public event PropertyChangedEventHandler PropertyChanged;
18+
19+
private ReferenceModel()
20+
{
21+
_info = new Lazy<ReferenceInfo>(GenerateInfo);
22+
}
1823

19-
public ReferenceModel(IVBProject project, int priority)
24+
public ReferenceModel(ReferenceInfo info, bool recent = false, bool pinned = false) : this()
25+
{
26+
Guid = info.Guid;
27+
Name = info.Name;
28+
FullPath = info.FullPath;
29+
Major = info.Major;
30+
Minor = info.Minor;
31+
IsRecent = recent;
32+
IsPinned = pinned;
33+
}
34+
35+
public ReferenceModel(IVBProject project, int priority) : this()
2036
{
2137
Name = project.Name ?? string.Empty;
2238
Priority = priority;
2339
Guid = Guid.Empty;
2440
Description = project.Description ?? string.Empty;
2541
FullPath = project.FileName ?? string.Empty;
2642
IsBuiltIn = false;
27-
Type = ReferenceKind.Project;
43+
Type = ReferenceKind.Project;
2844
}
2945

30-
public ReferenceModel(RegisteredLibraryInfo info)
46+
public ReferenceModel(RegisteredLibraryInfo info) : this()
3147
{
3248
Name = info.Name ?? string.Empty;
3349
Guid = info.Guid;
@@ -50,11 +66,11 @@ public ReferenceModel(RegisteredLibraryInfo info, IReference reference, int prio
5066
IsReferenced = true;
5167
}
5268

53-
public ReferenceModel(IReference reference, int priority)
69+
public ReferenceModel(IReference reference, int priority) : this()
5470
{
5571
Priority = priority;
5672
Name = reference.Name;
57-
Guid = new Guid(reference.Guid);
73+
Guid = Guid.TryParse(reference.Guid, out var guid) ? guid : Guid.Empty;
5874
Description = string.IsNullOrEmpty(reference.Description) ? Path.GetFileNameWithoutExtension(reference.FullPath) : reference.Description;
5975
Major = reference.Major;
6076
Minor = reference.Minor;
@@ -65,7 +81,7 @@ public ReferenceModel(IReference reference, int priority)
6581
Type = reference.Type;
6682
}
6783

68-
public ReferenceModel(ITypeLib reference)
84+
public ReferenceModel(ITypeLib reference) : this()
6985
{
7086
var documentation = new ComDocumentation(reference, -1);
7187
Name = documentation.Name;
@@ -83,10 +99,21 @@ public ReferenceModel(ITypeLib reference)
8399
}
84100
}
85101

86-
public ReferenceModel(string path)
102+
public ReferenceModel(string path, bool broken = false) : this()
87103
{
88104
FullPath = path;
89-
Name = Path.GetFileName(path);
105+
try
106+
{
107+
Name = Path.GetFileName(path);
108+
Description = Name;
109+
}
110+
catch
111+
{
112+
// Yeah, that's probably busted.
113+
IsBroken = true;
114+
}
115+
116+
IsBroken = broken;
90117
}
91118

92119
private bool _pinned;
@@ -106,19 +133,19 @@ public bool IsPinned
106133

107134
public int? Priority { get; set; }
108135

109-
public string Name { get; }
136+
public string Name { get; } = string.Empty;
110137
public Guid Guid { get; }
111-
public string Description { get; }
112-
public string FullPath { get; }
113-
public string LocaleName { get; }
138+
public string Description { get; } = string.Empty;
139+
public string FullPath { get; } = string.Empty;
140+
public string LocaleName { get; } = string.Empty;
114141

115142
public bool IsBuiltIn { get; }
116143
public bool IsBroken { get; }
117144
public TypeLibTypeFlags Flags { get; set; }
118145
public ReferenceKind Type { get; }
119146

120-
private string FullPath32 { get; }
121-
private string FullPath64 { get; }
147+
private string FullPath32 { get; } = string.Empty;
148+
private string FullPath64 { get; } = string.Empty;
122149
public int Major { get; set; }
123150
public int Minor { get; set; }
124151
public string Version => $"{Major}.{Minor}";
@@ -147,9 +174,17 @@ public ReferenceStatus Status
147174
}
148175
}
149176

150-
public ReferenceInfo ToReferenceInfo()
177+
private readonly Lazy<ReferenceInfo> _info;
178+
private ReferenceInfo GenerateInfo() => new ReferenceInfo(Guid, Name, FullPath, Major, Minor);
179+
public ReferenceInfo ToReferenceInfo() => _info.Value;
180+
181+
public bool Matches(ReferenceInfo info)
151182
{
152-
return new ReferenceInfo(Guid, Name, FullPath, Major, Minor);
183+
return Major == info.Major && Minor == info.Minor &&
184+
FullPath.Equals(info.FullPath, StringComparison.OrdinalIgnoreCase) ||
185+
FullPath32.Equals(info.FullPath, StringComparison.OrdinalIgnoreCase) ||
186+
FullPath64.Equals(info.FullPath, StringComparison.OrdinalIgnoreCase) ||
187+
Guid.Equals(info.Guid);
153188
}
154189

155190
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")

Rubberduck.Core/AddRemoveReferences/ReferenceReconciler.cs

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.IO;
33
using System.Linq;
44
using System.Runtime.InteropServices;
5-
using System.Text;
6-
using System.Threading.Tasks;
75
using Rubberduck.Interaction;
86
using Rubberduck.Parsing.ComReflection;
9-
using Rubberduck.Parsing.Symbols;
107
using Rubberduck.Resources;
118
using Rubberduck.Settings;
129
using Rubberduck.SettingsProvider;
1310
using Rubberduck.UI.AddRemoveReferences;
1411
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
15-
using Rubberduck.VBEditor.Utility;
1612

1713
namespace Rubberduck.AddRemoveReferences
1814
{
@@ -23,15 +19,16 @@ public interface IReferenceReconciler
2319
ReferenceModel TryAddReference(IVBProject project, string path);
2420
ReferenceModel TryAddReference(IVBProject project, ReferenceModel reference);
2521
ReferenceModel GetLibraryInfoFromPath(string path);
22+
void UpdateSettings(IAddRemoveReferencesModel model, bool recent = false);
2623
}
2724

2825
public class ReferenceReconciler : IReferenceReconciler
2926
{
3027
private readonly IMessageBox _messageBox;
31-
private readonly IConfigProvider<GeneralSettings> _settings;
28+
private readonly IConfigProvider<ReferenceSettings> _settings;
3229
private readonly IComLibraryProvider _tlbProvider;
3330

34-
public ReferenceReconciler(IMessageBox messageBox, IConfigProvider<GeneralSettings> settings, IComLibraryProvider tlbProvider)
31+
public ReferenceReconciler(IMessageBox messageBox, IConfigProvider<ReferenceSettings> settings, IComLibraryProvider tlbProvider)
3532
{
3633
_messageBox = messageBox;
3734
_settings = settings;
@@ -40,11 +37,22 @@ public ReferenceReconciler(IMessageBox messageBox, IConfigProvider<GeneralSettin
4037

4138
public void ReconcileReferences(IAddRemoveReferencesModel model)
4239
{
40+
if (model?.NewReferences is null || !model.NewReferences.Any())
41+
{
42+
return;
43+
}
44+
4345
ReconcileReferences(model, model.NewReferences.ToList());
4446
}
4547

48+
//TODO test for simple adds.
4649
public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model, List<ReferenceModel> allReferences)
4750
{
51+
if (model is null || allReferences is null || !allReferences.Any())
52+
{
53+
return new List<ReferenceModel>();
54+
}
55+
4856
var selected = allReferences.Where(reference => !reference.IsBuiltIn && reference.Priority.HasValue)
4957
.ToDictionary(reference => reference.FullPath);
5058

@@ -67,25 +75,38 @@ public List<ReferenceModel> ReconcileReferences(IAddRemoveReferencesModel model,
6775
reference.Dispose();
6876
}
6977
}
70-
7178
output.AddRange(selected.Values.OrderBy(selection => selection.Priority)
7279
.Select(reference => TryAddReference(project, reference)).Where(added => added != null));
7380
}
7481

82+
UpdateSettings(model, true);
7583
return output;
7684
}
7785

86+
private static readonly List<string> InterestingExtensions = new List<string> { ".olb", ".tlb", ".dll", ".ocx", ".exe" };
87+
7888
public ReferenceModel GetLibraryInfoFromPath(string path)
7989
{
8090
try
8191
{
82-
return new ReferenceModel(_tlbProvider.LoadTypeLibrary(path));
92+
var extension = Path.GetExtension(path)?.ToLowerInvariant() ?? string.Empty;
93+
if (string.IsNullOrEmpty(extension))
94+
{
95+
return null;
96+
}
97+
98+
// LoadTypeLibrary will attempt to open files in the host, so only attempt on possible COM servers.
99+
if (InterestingExtensions.Contains(extension))
100+
{
101+
return new ReferenceModel(_tlbProvider.LoadTypeLibrary(path));
102+
}
103+
return new ReferenceModel(path);
83104
}
84105
catch
85106
{
86-
// Most likely this is a project. If not, it we can't fail here because it could have come from the Apply
107+
// Most likely this is unloadable. If not, it we can't fail here because it could have come from the Apply
87108
// button in the AddRemoveReferencesDialog. Wait for it... :-P
88-
return new ReferenceModel(path);
109+
return new ReferenceModel(path, true);
89110
}
90111
}
91112

@@ -97,7 +118,7 @@ public ReferenceModel TryAddReference(IVBProject project, string path)
97118
{
98119
using (var reference = references.AddFromFile(path))
99120
{
100-
return reference is null ? null : new ReferenceModel(reference, references.Count);
121+
return reference is null ? null : new ReferenceModel(reference, references.Count) { IsRecent = true };
101122
}
102123
}
103124
catch (COMException ex)
@@ -117,6 +138,7 @@ public ReferenceModel TryAddReference(IVBProject project, ReferenceModel referen
117138
using (references.AddFromFile(reference.FullPath))
118139
{
119140
reference.Priority = references.Count;
141+
reference.IsRecent = true;
120142
return reference;
121143
}
122144
}
@@ -127,5 +149,27 @@ public ReferenceModel TryAddReference(IVBProject project, ReferenceModel referen
127149
return null;
128150
}
129151
}
152+
153+
public void UpdateSettings(IAddRemoveReferencesModel model, bool recent = false)
154+
{
155+
if (model?.Settings is null || model.References is null)
156+
{
157+
return;
158+
}
159+
160+
if (recent)
161+
{
162+
model.Settings.UpdateRecentReferencesForHost(model.HostApplication,
163+
model.References.Where(reference => reference.IsReferenced && !reference.IsBuiltIn)
164+
.Select(reference => reference.ToReferenceInfo()).ToList());
165+
166+
}
167+
168+
model.Settings.UpdatePinnedReferencesForHost(model.HostApplication,
169+
model.References.Where(reference => reference.IsPinned).Select(reference => reference.ToReferenceInfo())
170+
.ToList());
171+
172+
_settings.Save(model.Settings);
173+
}
130174
}
131175
}

Rubberduck.Core/Settings/GeneralSettings.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ public interface IGeneralSettings
2020
int MinimumLogLevel { get; set; }
2121
bool SetDpiUnaware { get; set; }
2222
List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; }
23-
int RecentReferencesTracked { get; set; }
24-
List<string> RecentReferences { get; set; }
25-
List<string> PinnedReferences { get; set; }
2623
}
2724

2825
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
@@ -64,10 +61,6 @@ public int MinimumLogLevel
6461

6562
public List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; } = new List<ExperimentalFeatures>();
6663

67-
public int RecentReferencesTracked { get; set; }
68-
public List<string> RecentReferences { get; set; }
69-
public List<string> PinnedReferences { get; set; }
70-
7164
public GeneralSettings()
7265
{
7366
//Enforce non-default default value for members
@@ -87,12 +80,9 @@ public bool Equals(GeneralSettings other)
8780
IsAutoSaveEnabled == other.IsAutoSaveEnabled &&
8881
AutoSavePeriod == other.AutoSavePeriod &&
8982
UserEditedLogLevel == other.UserEditedLogLevel &&
90-
MinimumLogLevel == other.MinimumLogLevel &&
91-
RecentReferencesTracked == other.RecentReferencesTracked &&
83+
MinimumLogLevel == other.MinimumLogLevel &&
9284
EnableExperimentalFeatures.Count == other.EnableExperimentalFeatures.Count &&
9385
EnableExperimentalFeatures.All(other.EnableExperimentalFeatures.Contains) &&
94-
RecentReferences.SequenceEqual(other.RecentReferences, StringComparer.OrdinalIgnoreCase) &&
95-
PinnedReferences.OrderBy(x => x).SequenceEqual(other.PinnedReferences.OrderBy(x => x), StringComparer.OrdinalIgnoreCase) &&
9686
SetDpiUnaware == other.SetDpiUnaware;
9787
}
9888
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using System.Reflection;
3+
using Rubberduck.Resources.Registration;
4+
using Rubberduck.SettingsProvider;
5+
using Rubberduck.VBEditor;
6+
7+
namespace Rubberduck.Settings
8+
{
9+
public class ReferenceConfigProvider : IConfigProvider<ReferenceSettings>
10+
{
11+
private readonly IPersistanceService<ReferenceSettings> _persister;
12+
13+
public ReferenceConfigProvider(IPersistanceService<ReferenceSettings> persister)
14+
{
15+
_persister = persister;
16+
}
17+
18+
public ReferenceSettings Create()
19+
{
20+
var defaults = CreateDefaults();
21+
return _persister.Load(defaults) ?? defaults;
22+
}
23+
24+
public ReferenceSettings CreateDefaults()
25+
{
26+
var defaults = new ReferenceSettings
27+
{
28+
RecentReferencesTracked = 20
29+
};
30+
31+
var version = Assembly.GetEntryAssembly().GetName().Version;
32+
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));
33+
defaults.PinReference(new ReferenceInfo(new Guid(RubberduckGuid.RubberduckApiTypeLibGuid), string.Empty, string.Empty, version.Major, version.Minor));
34+
35+
return defaults;
36+
}
37+
38+
public void Save(ReferenceSettings settings)
39+
{
40+
_persister.Save(settings);
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)