Skip to content

Commit 2223f39

Browse files
committed
Initial implementation of template subsystem
1 parent f7c152c commit 2223f39

File tree

11 files changed

+681
-2
lines changed

11 files changed

+681
-2
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Rubberduck.Templates
2+
{
3+
public interface ITemplate
4+
{
5+
string Name { get; }
6+
bool IsUserDefined { get; }
7+
string Caption { get; }
8+
string Description { get; }
9+
string Read();
10+
void Write(string content);
11+
}
12+
}

Rubberduck.Core/Templates/Template.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace Rubberduck.Templates
2+
{
3+
/// <remarks>
4+
/// Template can be either built-in or user-defined. For a built-in template, the
5+
/// metadata should be stored in the <see cref="Rubberduck.Resources.Templates"/>
6+
/// resource, with specific entries, currently Name, Caption, Description and Code.
7+
/// Due to the fact that we cannot strong-type the reference to the resource entries
8+
/// the class has unit tests to validate that the crucial elements are present in the
9+
/// resource to guard against runtime errors/unexpected behavior due to missing/malformed
10+
/// entries in the resources.
11+
/// </remarks>
12+
public class Template : ITemplate
13+
{
14+
private readonly ITemplateFileHandler _handler;
15+
public Template(string name, ITemplateFileHandler handler)
16+
{
17+
_handler = handler;
18+
19+
Name = name;
20+
IsUserDefined = VerifyIfUserDefined(name);
21+
22+
if (IsUserDefined)
23+
{
24+
//TODO: Devise a way for users to define their captions/descriptions simply
25+
Caption = Name;
26+
Description = Name;
27+
}
28+
else
29+
{
30+
VerifyFile(name, handler);
31+
(Caption, Description) = GetBuiltInMetaData(name);
32+
}
33+
}
34+
35+
public string Name { get; }
36+
public bool IsUserDefined { get; }
37+
public string Caption { get; }
38+
public string Description { get; }
39+
40+
public string Read() => _handler.Read();
41+
42+
public void Write(string content) => _handler.Write(content);
43+
44+
private static bool VerifyIfUserDefined(string name)
45+
{
46+
var builtInName = Resources.Templates.ResourceManager.GetString(name + "_Name");
47+
return builtInName == null || builtInName != name;
48+
}
49+
50+
private static void VerifyFile(string name, ITemplateFileHandler handler)
51+
{
52+
if (handler.Exists)
53+
{
54+
return;
55+
}
56+
57+
var content = Resources.Templates.ResourceManager.GetString(name + "_Code");
58+
handler.Write(content);
59+
}
60+
61+
private static (string caption, string description) GetBuiltInMetaData(string name)
62+
{
63+
var caption = Resources.Templates.ResourceManager.GetString(name + "_Caption");
64+
var description = Resources.Templates.ResourceManager.GetString(name + "_Description");
65+
66+
return (caption, description);
67+
}
68+
}
69+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using Rubberduck.SettingsProvider;
6+
7+
namespace Rubberduck.Templates
8+
{
9+
public interface ITemplateFileHandlerProvider
10+
{
11+
ITemplateFileHandler CreateTemplateFileHandler(string templateName);
12+
IEnumerable<string> GetTemplateNames();
13+
}
14+
15+
public class TemplateFileHandlerProvider : ITemplateFileHandlerProvider
16+
{
17+
private readonly string _rootPath;
18+
19+
public TemplateFileHandlerProvider(IPersistancePathProvider pathProvider)
20+
{
21+
_rootPath = pathProvider.DataFolderPath("Templates");
22+
}
23+
24+
public ITemplateFileHandler CreateTemplateFileHandler(string templateName)
25+
{
26+
if (!Directory.Exists(_rootPath))
27+
{
28+
Directory.CreateDirectory(_rootPath);
29+
}
30+
31+
var fullPath = Path.Combine(_rootPath, templateName);
32+
if (!Directory.Exists(Path.GetDirectoryName(fullPath)))
33+
{
34+
throw new InvalidOperationException("Cannot provide a path for where the parent directory do not exist");
35+
}
36+
return new TemplateFileHandler(fullPath);
37+
}
38+
39+
public IEnumerable<string> GetTemplateNames()
40+
{
41+
var info = new DirectoryInfo(_rootPath);
42+
return info.GetFiles().Select(file => file.Name).ToList();
43+
}
44+
}
45+
46+
public interface ITemplateFileHandler
47+
{
48+
bool Exists { get; }
49+
string Read();
50+
void Write(string content);
51+
}
52+
53+
public class TemplateFileHandler : ITemplateFileHandler
54+
{
55+
private readonly string _fullPath;
56+
57+
public TemplateFileHandler(string fullPath)
58+
{
59+
_fullPath = fullPath + (fullPath.EndsWith(".rdt") ? string.Empty : ".rdt");
60+
}
61+
62+
public bool Exists => File.Exists(_fullPath);
63+
64+
public string Read()
65+
{
66+
return Exists ? File.ReadAllText(_fullPath) : null;
67+
}
68+
69+
public void Write(string content)
70+
{
71+
File.WriteAllText(_fullPath, content);
72+
}
73+
}
74+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Globalization;
5+
using System.Linq;
6+
7+
namespace Rubberduck.Templates
8+
{
9+
public interface ITemplateProvider
10+
{
11+
ITemplate Load(string templateName);
12+
IEnumerable<Template> GetTemplates();
13+
}
14+
15+
public class TemplateProvider : ITemplateProvider
16+
{
17+
private readonly ITemplateFileHandlerProvider _provider;
18+
19+
public TemplateProvider(ITemplateFileHandlerProvider provider)
20+
{
21+
_provider = provider;
22+
}
23+
24+
public ITemplate Load(string templateName)
25+
{
26+
var handler = _provider.CreateTemplateFileHandler(templateName);
27+
return new Template(templateName, handler);
28+
}
29+
30+
private Lazy<IEnumerable<Template>> LazyList => new Lazy<IEnumerable<Template>>(() =>
31+
{
32+
var list = new List<Template>();
33+
var set = Rubberduck.Resources.Templates.ResourceManager.GetResourceSet(CultureInfo.CurrentCulture, true, true);
34+
35+
foreach (DictionaryEntry entry in set)
36+
{
37+
var key = (string)entry.Key;
38+
var value = (string) entry.Value;
39+
if (key.EndsWith("_Name"))
40+
{
41+
var handler = _provider.CreateTemplateFileHandler(value);
42+
list.Add(new Template(value, handler));
43+
}
44+
}
45+
46+
foreach (var templateName in _provider.GetTemplateNames())
47+
{
48+
if (list.Any(e => e.Name == templateName))
49+
{
50+
continue;
51+
}
52+
53+
var handler = _provider.CreateTemplateFileHandler(templateName);
54+
list.Add(new Template(templateName, handler));
55+
}
56+
57+
return list;
58+
});
59+
60+
public IEnumerable<Template> GetTemplates() => LazyList.Value;
61+
}
62+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using NLog;
2+
using Rubberduck.Navigation.CodeExplorer;
3+
using Rubberduck.Templates;
4+
using Rubberduck.UI.Command;
5+
using Rubberduck.VBEditor.SafeComWrappers;
6+
7+
namespace Rubberduck.UI.CodeExplorer.Commands
8+
{
9+
public class AddTemplateCommand : CommandBase
10+
{
11+
private readonly ITemplateProvider _provider;
12+
private readonly AddComponentCommand _addComponentCommand;
13+
14+
public AddTemplateCommand(ITemplateProvider provider, AddComponentCommand addComponentCommand) : base(LogManager.GetCurrentClassLogger())
15+
{
16+
_provider = provider;
17+
_addComponentCommand = addComponentCommand;
18+
}
19+
20+
protected override bool EvaluateCanExecute(object parameter)
21+
{
22+
var data = ((string templateName, CodeExplorerItemViewModel model)) parameter;
23+
return _addComponentCommand.CanAddComponent(data.model,
24+
new[]
25+
{
26+
ProjectType.HostProject, ProjectType.StandAlone, ProjectType.StandardExe, ProjectType.ActiveXExe
27+
});
28+
}
29+
30+
protected override void OnExecute(object parameter)
31+
{
32+
var data = ((string templateName, CodeExplorerItemViewModel model)) parameter;
33+
if (string.IsNullOrWhiteSpace(data.templateName))
34+
{
35+
return;
36+
}
37+
38+
var moduleText = GetTemplate(data.templateName);
39+
_addComponentCommand.AddComponent(data.model, moduleText); }
40+
41+
private string GetTemplate(string name)
42+
{
43+
return _provider.Load(name).Read();
44+
}
45+
}
46+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
using Rubberduck.Navigation.CodeExplorer;
5+
6+
namespace Rubberduck.UI.Converters
7+
{
8+
public class TemplateCommandParameterToTupleConverter : IMultiValueConverter
9+
{
10+
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
(string templateName, CodeExplorerItemViewModel model) data = (
13+
values[0] as string,
14+
values[1] as CodeExplorerItemViewModel);
15+
return data;
16+
}
17+
18+
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
19+
{
20+
var data = ((string templateName, CodeExplorerItemViewModel model))value;
21+
return new[] {(object) data.templateName, data.model};
22+
}
23+
}
24+
}

Rubberduck.Main/Root/RubberduckIoCInstaller.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ public void Install(IWindsorContainer container, IConfigurationStore store)
8989
container.Register(Component.For<Version>()
9090
.UsingFactoryMethod(() => Assembly.GetExecutingAssembly().GetName().Version)
9191
.LifestyleSingleton());
92-
9392
container.Register(Component.For<IProjectsProvider, IProjectsRepository>()
9493
.ImplementedBy<ProjectsRepository>()
9594
.LifestyleSingleton());

Rubberduck.Resources/Rubberduck.Resources.csproj

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@
1010
<ItemGroup>
1111
<Resource Include="**\*.png" />
1212
<Resource Include="**\*.bmp" />
13-
<Resource Include="**\*.txt" />
13+
<Resource Include="**\*.txt" Exclude="$(IntermediateOutputPath)\**" />
14+
</ItemGroup>
15+
<ItemGroup>
16+
<Compile Update="Templates.Designer.cs">
17+
<DesignTime>True</DesignTime>
18+
<AutoGen>True</AutoGen>
19+
<DependentUpon>Templates.resx</DependentUpon>
20+
</Compile>
21+
</ItemGroup>
22+
<ItemGroup>
23+
<EmbeddedResource Update="Templates.resx">
24+
<Generator>PublicResXFileCodeGenerator</Generator>
25+
<LastGenOutput>Templates.Designer.cs</LastGenOutput>
26+
</EmbeddedResource>
1427
</ItemGroup>
1528
</Project>

0 commit comments

Comments
 (0)