1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TemplateWizard;
using IServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
namespace QtVsTools.Package.CMake
{
using Core;
using Core.CMake;
using Microsoft.VisualStudio.Workspace.VSIntegration.UI;
using QtVsTools.Core.Common;
using VisualStudio;
using Wizards.Util;
internal class CMakeVsProject : IVsProject
{
private IFileSystemNode SelectedNode { get; set; }
public CMakeVsProject(IFileSystemNode node)
{
SelectedNode = node;
}
public int GenerateUniqueItemName(uint itemIdLoc, string extension, string baseName,
out string newItemName)
{
var files = Enumerable.Empty<string>();
try {
files = Directory.GetFiles(CMakeProject.ActiveProject.RootPath, baseName + "*",
SearchOption.AllDirectories);
} catch (Exception exception) {
exception.Log();
}
// extract base file names and select distinct values to calculate the unique name
var number = files.Select(Path.GetFileNameWithoutExtension).Distinct().Count();
newItemName = $"{baseName}{(number > 0 ? number : "")}{extension}";
return VSConstants.S_OK;
}
public int AddItem(uint itemIdLoc, VSADDITEMOPERATION addItemOperation, string itemName,
uint numberOfFilesToOpen, string[] filesToOpen, IntPtr dialogOwner, VSADDRESULT[] result)
{
if (result is not { Length: not 0 })
return VSConstants.E_FAIL;
try {
var value = AddItemPrivate(addItemOperation, itemName, filesToOpen);
result[0] = value == VSConstants.S_OK
? VSADDRESULT.ADDRESULT_Success
: VSADDRESULT.ADDRESULT_Failure;
return value;
} catch (NotSupportedException exception) {
exception.Log();
Messages.DisplayErrorMessage("This item wizard does only support adding Qt items.");
return VSConstants.E_FAIL;
}
}
private int AddItemPrivate(VSADDITEMOPERATION addItemOperation, string safeItemName,
string[] filesToOpen)
{
if (filesToOpen is not { Length: not 0 })
throw new NotSupportedException("Missing file to open.");
if (addItemOperation != VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD)
throw new NotSupportedException("Item operations was not run wizard.");
if (!string.Equals(Path.GetExtension(filesToOpen[0]), ".vstemplate", Utils.IgnoreCase))
throw new NotSupportedException("No .vstemplate file was provided.");
var vsTemplate = new VsTemplate(filesToOpen[0]);
if (!vsTemplate.IsValid)
throw new NotSupportedException(".vstemplate file was not a Qt template.");
if (VsServiceProvider.GetService<EnvDTE.DTE, EnvDTE.DTE>() is not { } dte)
return VSConstants.E_FAIL;
var targetPath = SelectedNode switch
{
IFolderNode => SelectedNode.FullPath,
IFileNode => Path.GetDirectoryName(SelectedNode.FullPath),
_ => null
};
if (string.IsNullOrEmpty(targetPath))
return VSConstants.E_FAIL;
try {
var templatePath = Path.GetDirectoryName(filesToOpen[0]);
if (string.IsNullOrEmpty(targetPath) || string.IsNullOrEmpty(templatePath))
return VSConstants.E_FAIL;
var projectItems = vsTemplate.ProjectItems.ToList();
if (string.IsNullOrEmpty(vsTemplate.Assembly)) {
if (projectItems.Count > 1) // Might be the case if we could not extract the
return VSConstants.E_FAIL; // the assembly name from the .vstemplate file.
File.Copy( // Templates without wizard, just copy the file(s).
Path.Combine(templatePath, projectItems.ElementAt(0).TemplateFileName),
Path.Combine(targetPath, safeItemName));
return VSConstants.S_OK;
}
var assembly = Assembly.Load(vsTemplate.Assembly);
if (assembly == null || assembly.GetType(vsTemplate.FullClassName) is not { } type)
return VSConstants.E_FAIL;
if (Activator.CreateInstance(type) is not IWizard wizard)
return VSConstants.E_FAIL;
var replacements = new Dictionary<string, string>
{
{
"$safeitemname$", safeItemName
}
};
wizard.RunStarted(dte, replacements, WizardRunKind.AsNewItem, null);
foreach (var projectItem in projectItems) {
if (!replacements.TryGetValue(projectItem.TargetFileName, out var target))
return VSConstants.E_FAIL;
target = Path.Combine(targetPath, target);
File.Copy(Path.Combine(templatePath, projectItem.TemplateFileName), target);
if (projectItem.ReplaceParameters) {
var fileContent = File.ReadAllText(target);
fileContent = replacements.Aggregate(fileContent, (current, pair)
=> current.Replace(pair.Key, pair.Value));
File.WriteAllText(target, fileContent);
}
TextAndWhitespace.Adjust(dte, target);
}
} catch (Exception exception) {
exception.Log();
return VSConstants.E_FAIL;
}
return VSConstants.S_OK;
}
#region ### BOILERPLATE ###################################################################
public int IsDocumentInProject(string documentMoniker, out int documentFound,
VSDOCUMENTPRIORITY[] priorityLevel, out uint itemId)
{
documentFound = 0;
itemId = 0u;
return VSConstants.E_NOTIMPL;
}
public int GetMkDocument(uint itemId, out string documentMoniker)
{
documentMoniker = null;
return VSConstants.E_NOTIMPL;
}
public int OpenItem(uint itemId, ref Guid guidLogicalView, IntPtr documentDataExisting,
out IVsWindowFrame windowFrame)
{
windowFrame = null;
return VSConstants.E_NOTIMPL;
}
public int GetItemContext(uint itemId, out IServiceProvider serviceProvider)
{
serviceProvider = null;
return VSConstants.E_NOTIMPL;
}
#endregion ### BOILERPLATE ################################################################
}
}
|