| /****************************************************************************  | 
| **  | 
| ** Copyright (C) 2020 The Qt Company Ltd.  | 
| ** Contact: https://www.qt.io/licensing/  | 
| **  | 
| ** This file is part of the Qt VS Tools.  | 
| **  | 
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$  | 
| ** Commercial License Usage  | 
| ** Licensees holding valid commercial Qt licenses may use this file in  | 
| ** accordance with the commercial license agreement provided with the  | 
| ** Software or, alternatively, in accordance with the terms contained in  | 
| ** a written agreement between you and The Qt Company. For licensing terms  | 
| ** and conditions see https://www.qt.io/terms-conditions. For further  | 
| ** information use the contact form at https://www.qt.io/contact-us.  | 
| **  | 
| ** GNU General Public License Usage  | 
| ** Alternatively, this file may be used under the terms of the GNU  | 
| ** General Public License version 3 as published by the Free Software  | 
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  | 
| ** included in the packaging of this file. Please review the following  | 
| ** information to ensure the GNU General Public License requirements will  | 
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html.  | 
| **  | 
| ** $QT_END_LICENSE$  | 
| **  | 
| ****************************************************************************/  | 
|   | 
| using System;  | 
| using System.Collections.Generic;  | 
| using System.Diagnostics;  | 
| using System.IO;  | 
| using System.Linq;  | 
| using System.Text;  | 
| using System.Text.RegularExpressions;  | 
|   | 
| using EnvDTE;  | 
| using Microsoft.Internal.VisualStudio.PlatformUI;  | 
| using Microsoft.VisualStudio.Shell.Interop;  | 
| using Microsoft.VisualStudio.TemplateWizard;  | 
|   | 
| using QtVsTools.Common;  | 
| using QtVsTools.VisualStudio;  | 
|   | 
| using QtVsTools.Core;  | 
| using QtVsTools.Core.QtMsBuild;  | 
|   | 
| namespace QtVsTools.Wizards.ProjectWizard  | 
| {  | 
|     using static EnumExt;  | 
|     using WhereConfig = Func<IWizardConfiguration, bool>;  | 
|   | 
|     public interface IWizardConfiguration  | 
|     {  | 
|         string Name { get; }  | 
|         VersionInformation QtVersion { get; }  | 
|         string QtVersionName { get; }  | 
|         string QtVersionPath { get; }  | 
|         string Target { get; }  | 
|         string Platform { get; }  | 
|         bool IsDebug { get; }  | 
|         IEnumerable<string> Modules { get; }  | 
|     }  | 
|   | 
|     public enum ProjectTargets  | 
|     {  | 
|         Windows,  | 
|         [String("Windows Store")] WindowsStore,  | 
|         [String("Linux (SSH)")] LinuxSSH,  | 
|         [String("Linux (WSL)")] LinuxWSL  | 
|     }  | 
|   | 
|     public enum ProjectPlatforms  | 
|     {  | 
|         [String("x64")] X64,  | 
|         Win32,  | 
|         ARM64,  | 
|         ARM,  | 
|     }  | 
|   | 
|     public abstract class ProjectTemplateWizard : IWizard  | 
|     {  | 
|         protected readonly WhereConfig WhereConfig_SelectAll = (x => true);  | 
|   | 
|         protected struct ItemProperty  | 
|         {  | 
|             public string Key { get; }  | 
|             public string Value { get; }  | 
|             public WhereConfig WhereConfig { get; }  | 
|   | 
|             public ItemProperty(string key, string value, WhereConfig whereConfig = null)  | 
|             {  | 
|                 Key = key;  | 
|                 Value = value;  | 
|                 WhereConfig = whereConfig;  | 
|             }  | 
|   | 
|             public static implicit operator ItemProperty[](ItemProperty that)  | 
|             {  | 
|                 return new[] { that };  | 
|             }  | 
|         }  | 
|   | 
|         protected class ItemGlobalDef  | 
|         {  | 
|             public string ItemType { get; set; }  | 
|             public ItemProperty[] Properties { get; set; }  | 
|         }  | 
|   | 
|         protected class ItemDef  | 
|         {  | 
|             public string ItemType { get; set; }  | 
|             public string Include { get; set; }  | 
|             public ItemProperty[] Properties { get; set; }  | 
|             public string Filter { get; set; }  | 
|             public WhereConfig WhereConfig { get; set; }  | 
|         }  | 
|   | 
|         // keep in sync with QtVsTools.Core.TemplateType  | 
|   | 
|         [Flags]  | 
|         protected enum Options : uint  | 
|         {  | 
|             Application = 0x000,  | 
|             DynamicLibrary = 0x001,  | 
|             StaticLibrary = 0x002,  | 
|             GUISystem = 0x004,  | 
|             ConsoleSystem = 0x008,  | 
|             PluginProject = 0x100  | 
|         }  | 
|   | 
|         protected abstract Options TemplateType { get; }  | 
|         protected abstract WizardData WizardData { get; }  | 
|         protected abstract WizardWindow WizardWindow { get; }  | 
|   | 
|         protected virtual IDictionary<string, ItemGlobalDef> ItemGlobals => null;  | 
|         protected virtual IEnumerable<ItemDef> ExtraItems => Enumerable.Empty<ItemDef>();  | 
|         protected virtual IEnumerable<string> ExtraModules => Enumerable.Empty<string>();  | 
|         protected virtual IEnumerable<string> ExtraDefines => Enumerable.Empty<string>();  | 
|   | 
|         protected virtual IEnumerable<IWizardConfiguration> Configurations => WizardData.Configs;  | 
|         protected virtual bool UsePrecompiledHeaders => WizardData.UsePrecompiledHeader;  | 
|   | 
|         protected Dictionary<string, string> ParameterValues { get; private set; }  | 
|         protected EnvDTE.DTE Dte { get; private set; }  | 
|   | 
|         ItemDef _PrecompiledHeaderFile;  | 
|         protected virtual ItemDef PrecompiledHeader => _PrecompiledHeaderFile  | 
|             ?? (_PrecompiledHeaderFile = new ItemDef  | 
|             {  | 
|                 ItemType = "ClInclude",  | 
|                 Include = "stdafx.h",  | 
|                 Filter = "Header Files"  | 
|             });  | 
|   | 
|         ItemDef _PrecompiledHeaderSourceFile;  | 
|         protected virtual ItemDef PrecompiledHeaderSource => _PrecompiledHeaderSourceFile  | 
|             ?? (_PrecompiledHeaderSourceFile = new ItemDef  | 
|             {  | 
|                 ItemType = "ClCompile",  | 
|                 Include = "stdafx.cpp",  | 
|                 Properties = new ItemProperty("PrecompiledHeader", "Create"),  | 
|                 Filter = "Source Files",  | 
|             });  | 
|   | 
|         protected class TemplateParameters  | 
|         {  | 
|             public ProjectTemplateWizard Template { get; set; }  | 
|   | 
|             string ParamKey(Enum param)  | 
|             {  | 
|                 return string.Format("${0}$", param.Cast<string>());  | 
|             }  | 
|   | 
|             public string this[Enum param]  | 
|             {  | 
|                 get => Template.ParameterValues[ParamKey(param)];  | 
|                 set => Template.ParameterValues[ParamKey(param)] = value;  | 
|             }  | 
|         }  | 
|   | 
|         protected enum NewProject  | 
|         {  | 
|             // Read-only parameters  | 
|             [String("projectname")] Name,  | 
|             [String("safeprojectname")] SafeName,  | 
|             [String("destinationdirectory")] DestinationDirectory,  | 
|             [String("solutiondirectory")] SolutionDirectory,  | 
|   | 
|             // Custom parameters  | 
|             ToolsVersion,  | 
|             ProjectConfigurations,  | 
|             Properties,  | 
|             ProjectGuid,  | 
|             Keyword,  | 
|             Globals,  | 
|             Configurations,  | 
|             PropertySheets,  | 
|             QtSettings,  | 
|             BuildSettings,  | 
|             ProjectItems,  | 
|             FilterItems,  | 
|         }  | 
|   | 
|         TemplateParameters _Parameter;  | 
|         protected TemplateParameters Parameter => _Parameter  | 
|             ?? (_Parameter = new TemplateParameters { Template = this });  | 
|   | 
|         protected QtVersionManager VersionManager => QtVersionManager.The();  | 
|   | 
|         public virtual void ProjectItemFinishedGenerating(ProjectItem projectItem) { }  | 
|         public virtual void BeforeOpeningFile(ProjectItem projectItem) { }  | 
|         public virtual void RunFinished() { }  | 
|         public virtual bool ShouldAddProjectItem(string filePath) => true;  | 
|   | 
|         protected virtual void BeforeWizardRun() { }  | 
|         protected virtual void BeforeTemplateExpansion() { }  | 
|         protected virtual void OnProjectGenerated(Project project) { }  | 
|   | 
|         public virtual void RunStarted(  | 
|             object automationObject,  | 
|             Dictionary<string, string> parameterValues,  | 
|             WizardRunKind runKind,  | 
|             object[] customParams)  | 
|         {  | 
|             Dte = automationObject as DTE;  | 
|             ParameterValues = parameterValues;  | 
|   | 
|             Debug.Assert(WizardWindow != null);  | 
|   | 
|             BeforeWizardRun();  | 
|   | 
|             var iVsUIShell = VsServiceProvider.GetService<SVsUIShell, IVsUIShell>();  | 
|             if (iVsUIShell == null)  | 
|                 throw new NullReferenceException("IVsUIShell");  | 
|   | 
|             try {  | 
|                 IntPtr hwnd;  | 
|                 iVsUIShell.EnableModeless(0);  | 
|                 iVsUIShell.GetDialogOwnerHwnd(out hwnd);  | 
|                 WindowHelper.ShowModal(WizardWindow, hwnd);  | 
|             } catch (QtVSException exception) {  | 
|                 Messages.DisplayErrorMessage(exception.Message);  | 
|                 throw;  | 
|             } finally {  | 
|                 iVsUIShell.EnableModeless(1);  | 
|             }  | 
|             if (!WizardWindow.DialogResult ?? false) {  | 
|                 try {  | 
|                     Directory.Delete(Parameter[NewProject.DestinationDirectory]);  | 
|                     Directory.Delete(Parameter[NewProject.SolutionDirectory]);  | 
|                 } catch { }  | 
|                 throw new WizardBackoutException();  | 
|             }  | 
|   | 
|             BeforeTemplateExpansion();  | 
|             Expand();  | 
|         }  | 
|   | 
|         public virtual void ProjectFinishedGenerating(Project project)  | 
|         {  | 
|             OnProjectGenerated(project);  | 
|         }  | 
|   | 
|         protected static bool IsLinux(IWizardConfiguration wizConfig)  | 
|         {  | 
|             return wizConfig.Target.EqualTo(ProjectTargets.LinuxSSH)  | 
|                 || wizConfig.Target.EqualTo(ProjectTargets.LinuxWSL);  | 
|         }  | 
|   | 
|         protected static string GetLinuxCompilerPath(IWizardConfiguration wizConfig)  | 
|         {  | 
|             if (!IsLinux(wizConfig))  | 
|                 return string.Empty;  | 
|             if (string.IsNullOrEmpty(wizConfig.QtVersionPath))  | 
|                 return string.Empty;  | 
|             string[] linuxPaths = wizConfig.QtVersionPath.Split(':');  | 
|             if (linuxPaths == null || linuxPaths.Length <= 2)  | 
|                 return string.Empty;  | 
|             return linuxPaths[2];  | 
|         }  | 
|   | 
|         protected virtual void Expand()  | 
|         {  | 
|             Debug.Assert(ParameterValues != null);  | 
|             Debug.Assert(Dte != null);  | 
|             Debug.Assert(Configurations != null);  | 
|             Debug.Assert(ExtraItems != null);  | 
|   | 
|             StringBuilder xml;  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Tools version = VS version  | 
|             //  | 
|             Parameter[NewProject.ToolsVersion] = Dte.Version;  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Configurations  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|     <ProjectConfiguration Include=""{0}|{1}"">  | 
|       <Configuration>{0}</Configuration>  | 
|       <Platform>{1}</Platform>  | 
|     </ProjectConfiguration>",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|             }  | 
|             Parameter[NewProject.ProjectConfigurations] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Properties  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|   <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|                 if (IsLinux(c)) {  | 
|                     var compilerPath = GetLinuxCompilerPath(c);  | 
|                     if (!string.IsNullOrEmpty(compilerPath))  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <RemoteCCompileToolExe>{0}</RemoteCCompileToolExe>  | 
|       <RemoteCppCompileToolExe>{0}</RemoteCppCompileToolExe>  | 
|       <RemoteLdToolExe>{0}</RemoteLdToolExe>",  | 
|                             /*{0}*/ compilerPath));  | 
|                 }  | 
|                 xml.AppendLine(@"  | 
|   </PropertyGroup>");  | 
|             }  | 
|             Parameter[NewProject.Properties] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Globals  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             Parameter[NewProject.ProjectGuid] = HelperFunctions.NewProjectGuid();  | 
|             Parameter[NewProject.Keyword] = Resources.QtVSVersionTag;  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Globals: Windows  | 
|             //  | 
|             foreach (IWizardConfiguration c in Configurations  | 
|                 .Where(c => c.Target.EqualTo(ProjectTargets.Windows))) {  | 
|                 if (!string.IsNullOrEmpty(c.QtVersion.VC_WindowsTargetPlatformVersion)) {  | 
|                     xml.AppendLine(string.Format(@"  | 
|     <WindowsTargetPlatformVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{2}</WindowsTargetPlatformVersion>",  | 
|                         /*{0}*/ c.Name,  | 
|                         /*{1}*/ c.Platform,  | 
|                         /*{2}*/ c.QtVersion.VC_WindowsTargetPlatformVersion));  | 
|                 }  | 
|             }  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Globals: Windows Store  | 
|             //  | 
|             foreach (IWizardConfiguration c in Configurations  | 
|                 .Where(c => c.Target.EqualTo(ProjectTargets.WindowsStore))) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|     <ApplicationType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Windows Store</ApplicationType>  | 
|     <WindowsTargetPlatformVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{2}</WindowsTargetPlatformVersion>  | 
|     <WindowsTargetPlatformMinVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{3}</WindowsTargetPlatformMinVersion>  | 
|     <MinimumVisualStudioVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{4}</MinimumVisualStudioVersion>  | 
|     <ApplicationTypeRevision Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{5}</ApplicationTypeRevision>  | 
|     <DefaultLanguage Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">en</DefaultLanguage>  | 
|     <AppContainerApplication Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">true</AppContainerApplication>",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform,  | 
|                     /*{2}*/ c.QtVersion.VC_WindowsTargetPlatformVersion,  | 
|                     /*{3}*/ c.QtVersion.VC_WindowsTargetPlatformMinVersion,  | 
|                     /*{4}*/ c.QtVersion.VC_MinimumVisualStudioVersion,  | 
|                     /*{5}*/ c.QtVersion.VC_ApplicationTypeRevision));  | 
|             }  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Globals: Linux  | 
|             //  | 
|             foreach (IWizardConfiguration c in Configurations.Where(c => IsLinux(c))) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|     <ApplicationType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Linux</ApplicationType>  | 
|     <ApplicationTypeRevision Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">1.0</ApplicationTypeRevision>  | 
|     <TargetLinuxPlatform Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Generic</TargetLinuxPlatform>  | 
|     <LinuxProjectType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{{D51BCBC9-82E9-4017-911E-C93873C4EA2B}}</LinuxProjectType>",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|             }  | 
|   | 
|             Parameter[NewProject.Globals] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // VC Configurations  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 ProjectTargets target;  | 
|                 if (!c.Target.TryCast(out target))  | 
|                     continue;  | 
|                 xml.AppendLine(string.Format(@"  | 
|   <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""Configuration"">",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|                 if (TemplateType.HasFlag(Options.DynamicLibrary)) {  | 
|                     xml.AppendLine(@"  | 
|     <ConfigurationType>DynamicLibrary</ConfigurationType>");  | 
|                 } else if (TemplateType.HasFlag(Options.StaticLibrary)) {  | 
|                     xml.AppendLine(@"  | 
|     <ConfigurationType>StaticLibrary</ConfigurationType>");  | 
|                 } else {  | 
|                     xml.AppendLine(@"  | 
|     <ConfigurationType>Application</ConfigurationType>");  | 
|                 }  | 
|                 switch (target) {  | 
|                 case ProjectTargets.Windows:  | 
|                 case ProjectTargets.WindowsStore:  | 
|                     xml.AppendLine(string.Format(@"  | 
|     <PlatformToolset>v{0}</PlatformToolset>",  | 
|                         /*{0}*/ BuildConfig.PlatformToolset));  | 
|                     break;  | 
|                 case ProjectTargets.LinuxSSH:  | 
|                     xml.AppendLine(@"  | 
|     <PlatformToolset>Remote_GCC_1_0</PlatformToolset>");  | 
|                     break;  | 
|                 case ProjectTargets.LinuxWSL:  | 
|                     xml.AppendLine(@"  | 
|     <PlatformToolset>WSL_1_0</PlatformToolset>");  | 
|                     break;  | 
|                 }  | 
|                 if (IsLinux(c)) {  | 
|                     xml.AppendLine(string.Format(@"  | 
|     <UseDebugLibraries>{0}</UseDebugLibraries>",  | 
|                         /*{0}*/ c.IsDebug ? "true" : "false"));  | 
|                 } else if (target == ProjectTargets.WindowsStore) {  | 
|                     xml.AppendLine(@"  | 
|     <GenerateManifest>false</GenerateManifest>  | 
|     <EmbedManifest>false</EmbedManifest>");  | 
|                 }  | 
|                 xml.AppendLine(@"  | 
|   </PropertyGroup>");  | 
|             }  | 
|             Parameter[NewProject.Configurations] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Property sheets  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|   <ImportGroup Label=""PropertySheets"" Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">  | 
|     <Import Project=""$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"" Condition=""exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"" Label=""LocalAppDataPlatform"" />  | 
|     <Import Project=""$(QtMsBuild)\Qt.props"" />  | 
|   </ImportGroup>",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|             }  | 
|             Parameter[NewProject.PropertySheets] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Qt settings  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|   <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""QtSettings"">  | 
|     <QtInstall>{2}</QtInstall>  | 
|     <QtModules>{3}</QtModules>  | 
|     <QtBuildConfig>{4}</QtBuildConfig>",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform,  | 
|                     /*{2}*/ c.QtVersionName,  | 
|                     /*{3}*/ string.Join(";", c.Modules.Union(ExtraModules)),  | 
|                     /*{4}*/ c.IsDebug ? "debug" : "release"));  | 
|                 if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {  | 
|                     xml.AppendLine(@"  | 
|     <QtDeploy>true</QtDeploy>  | 
|     <QtDeployToProjectDir>true</QtDeployToProjectDir>  | 
|     <QtDeployVsContent>true</QtDeployVsContent>");  | 
|                 }  | 
|                 xml.AppendLine(@"  | 
|   </PropertyGroup>");  | 
|             }  | 
|             Parameter[NewProject.QtSettings] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Build settings  | 
|             //  | 
|             IEnumerable<ItemProperty> mocProperties  | 
|                 = ItemGlobals?[QtMoc.ItemTypeName]?.Properties ?? Enumerable.Empty<ItemProperty>();  | 
|             IEnumerable<ItemProperty> clProperties  | 
|                 = ItemGlobals?["ClCompile"]?.Properties ?? Enumerable.Empty<ItemProperty>();  | 
|             IEnumerable<ItemProperty> linkProperties  | 
|                 = ItemGlobals?["Link"]?.Properties ?? Enumerable.Empty<ItemProperty>();  | 
|   | 
|             xml = new StringBuilder();  | 
|             foreach (IWizardConfiguration c in Configurations) {  | 
|                 xml.AppendLine(string.Format(@"  | 
|   <ItemDefinitionGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""Configuration"">",  | 
|                     /*{0}*/ c.Name,  | 
|                     /*{1}*/ c.Platform));  | 
|   | 
|   | 
|                 ///////////////////////////////////////////////////////////////////////////////////  | 
|                 // Build settings: C++ compiler  | 
|                 //  | 
|                 if (!IsLinux(c)) {  | 
|                     // Windows  | 
|                     xml.AppendLine(@"  | 
|     <ClCompile>  | 
|       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>  | 
|       <MultiProcessorCompilation>true</MultiProcessorCompilation>");  | 
|                     if (c.IsDebug) {  | 
|                         xml.AppendLine(@"  | 
|       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>  | 
|       <Optimization>Disabled</Optimization>  | 
|       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>");  | 
|                     } else {  | 
|                         xml.AppendLine(@"  | 
|       <DebugInformationFormat>None</DebugInformationFormat>  | 
|       <Optimization>MaxSpeed</Optimization>  | 
|       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>");  | 
|                     }  | 
|                     if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {  | 
|                         xml.AppendLine(@"  | 
|       <CompileAsWinRT>false</CompileAsWinRT>  | 
|       <PrecompiledHeader>NotUsing</PrecompiledHeader>  | 
|       <RuntimeTypeInfo>true</RuntimeTypeInfo>");  | 
|                     }  | 
|                     if (UsePrecompiledHeaders) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <UsePrecompiledHeader>Use</UsePrecompiledHeader>  | 
|       <PrecompiledHeaderFile>{0}</PrecompiledHeaderFile>",  | 
|                             /*{0}*/ PrecompiledHeader.Include));  | 
|                     }  | 
|                     if (ExtraDefines?.Any() == true) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <PreprocessorDefinitions>{0};%(PreprocessorDefinitions)</PreprocessorDefinitions>",  | 
|                             /*{0}*/ string.Join(";", ExtraDefines)));  | 
|                     }  | 
|                     foreach (ItemProperty p in clProperties) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <{0}>{1}</{0}>",  | 
|                             /*{0}*/ p.Key,  | 
|                             /*{1}*/ p.Value));  | 
|                     }  | 
|                     xml.AppendLine(@"  | 
|     </ClCompile>");  | 
|                 } else {  | 
|                     // Linux  | 
|                     xml.AppendLine(@"  | 
|     <ClCompile>  | 
|       <PositionIndependentCode>true</PositionIndependentCode>  | 
|     </ClCompile>");  | 
|                 }  | 
|   | 
|                 ///////////////////////////////////////////////////////////////////////////////////  | 
|                 // Build settings: Linker  | 
|                 //  | 
|                 if (!IsLinux(c)) {  | 
|                     // Windows  | 
|                     xml.AppendLine(string.Format(@"  | 
|     <Link>  | 
|       <SubSystem>{0}</SubSystem>  | 
|       <GenerateDebugInformation>{1}</GenerateDebugInformation>",  | 
|                         /*{0}*/ TemplateType.HasFlag(Options.ConsoleSystem) ? "Console" : "Windows",  | 
|                         /*{1}*/ c.IsDebug ? "true" : "false"));  | 
|                     if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <AdditionalOptions>/APPCONTAINER %(AdditionalOptions)</AdditionalOptions>  | 
|       <GenerateManifest>false</GenerateManifest>  | 
|       <GenerateWindowsMetadata>false</GenerateWindowsMetadata>  | 
|       <TargetMachine>{0}</TargetMachine>",  | 
|                             /*{0}*/ c.QtVersion.VC_Link_TargetMachine));  | 
|                     }  | 
|                     foreach (ItemProperty p in linkProperties) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <{0}>{1}</{0}>",  | 
|                             /*{0}*/ p.Key,  | 
|                             /*{1}*/ p.Value));  | 
|                     }  | 
|                     xml.AppendLine(@"  | 
|     </Link>");  | 
|                 }  | 
|   | 
|                 ///////////////////////////////////////////////////////////////////////////////////  | 
|                 // Build settings: moc  | 
|                 //  | 
|                 if (UsePrecompiledHeaders || mocProperties.Any()) {  | 
|                     xml.AppendLine(string.Format(@"  | 
|     <{0}>", QtMoc.ItemTypeName));  | 
|                     foreach (ItemProperty p in mocProperties) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <{0}>{1}</{0}>",  | 
|                             /*{0}*/ p.Key,  | 
|                             /*{1}*/ p.Value));  | 
|                     }  | 
|                     if (UsePrecompiledHeaders) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <{0}>{1};%({0})</{0}>",  | 
|                             /*{0}*/ QtMoc.Property.PrependInclude,  | 
|                             /*{1}*/ PrecompiledHeader.Include));  | 
|                     }  | 
|                     xml.AppendLine(string.Format(@"  | 
|     </{0}>", QtMoc.ItemTypeName));  | 
|                 }  | 
|   | 
|                 ///////////////////////////////////////////////////////////////////////////////////  | 
|                 // Build settings: remaining item types  | 
|                 //  | 
|                 if (ItemGlobals != null) {  | 
|                     foreach (string itemType in ItemGlobals.Keys  | 
|                         .Except(new[] { "ClCompile", "Link", QtMoc.ItemTypeName })) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|     <{0}>",  | 
|                             /*{0}*/ itemType));  | 
|                         foreach (ItemProperty p in ItemGlobals[itemType].Properties) {  | 
|                             xml.AppendLine(string.Format(@"  | 
|       <{0}>{1}</{0}>",  | 
|                                 /*{0}*/ p.Key,  | 
|                                 /*{1}*/ p.Value));  | 
|                         }  | 
|                         xml.AppendLine(string.Format(@"  | 
|     </{0}>",  | 
|                             /*{0}*/ itemType));  | 
|                     }  | 
|                 }  | 
|                 xml.AppendLine(@"  | 
|   </ItemDefinitionGroup>");  | 
|             }  | 
|   | 
|             Parameter[NewProject.BuildSettings] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Project items  | 
|             //  | 
|             IEnumerable<ItemDef> projectItems = ExtraItems  | 
|                 .Where((ItemDef item) => item.WhereConfig == null  | 
|                     || Configurations.Where(item.WhereConfig).Any())  | 
|                 .Union(UsePrecompiledHeaders  | 
|                     ? new[] { PrecompiledHeader, PrecompiledHeaderSource }  | 
|                     : Enumerable.Empty<ItemDef>());  | 
|   | 
|             xml = new StringBuilder();  | 
|             foreach (ItemDef item in projectItems) {  | 
|                 bool itemHasProperties = (item.WhereConfig != null || item.Properties != null);  | 
|                 xml.Append(string.Format(@"  | 
|     <{0} Include=""{1}""{2}",  | 
|                     /*{0}*/ item.ItemType,  | 
|                     /*{1}*/ item.Include,  | 
|                     /*{2}*/ itemHasProperties ? ">" : " />"));  | 
|   | 
|                 if (item.Properties != null) {  | 
|                     foreach (ItemProperty property in item.Properties) {  | 
|                         IEnumerable<IWizardConfiguration> configs = Configurations  | 
|                             .Where(property.WhereConfig ?? WhereConfig_SelectAll);  | 
|                         foreach (IWizardConfiguration config in configs) {  | 
|                             xml.AppendLine(string.Format(@"  | 
|       <{0} Condition=""'$(Configuration)|$(Platform)' == '{1}|{2}'"">{3}</{0}>",  | 
|                                 /*{0}*/ property.Key,  | 
|                                 /*{1}*/ config.Name,  | 
|                                 /*{2}*/ config.Platform,  | 
|                                 /*{3}*/ property.Value));  | 
|                         }  | 
|                     }  | 
|                 }  | 
|   | 
|                 if (item.WhereConfig != null) {  | 
|                     IEnumerable<IWizardConfiguration> excludedConfigs = Configurations  | 
|                         .Where(config => !item.WhereConfig(config));  | 
|                     foreach (var excludedConfig in excludedConfigs) {  | 
|                         xml.AppendLine(string.Format(@"  | 
|       <ExcludedFromBuild Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">true</ExcludedFromBuild>",  | 
|                             /*{0}*/ excludedConfig.Name,  | 
|                             /*{1}*/ excludedConfig.Platform));  | 
|                     }  | 
|                 }  | 
|   | 
|                 if (itemHasProperties) {  | 
|                     xml.AppendLine(string.Format(@"  | 
|     </{0}>",  | 
|                         /*{0}*/ item.ItemType));  | 
|                 }  | 
|             }  | 
|             Parameter[NewProject.ProjectItems] = FormatParam(xml);  | 
|   | 
|             ///////////////////////////////////////////////////////////////////////////////////////  | 
|             // Project items: filters  | 
|             //  | 
|             xml = new StringBuilder();  | 
|             foreach (ItemDef item in projectItems) {  | 
|                 xml.Append(string.Format(@"  | 
|     <{0} Include=""{1}"">",  | 
|                     /*{0}*/ item.ItemType,  | 
|                     /*{1}*/ item.Include));  | 
|                 xml.AppendLine(string.Format(@"  | 
|       <Filter>{0}</Filter>",  | 
|                     /*{0}*/ item.Filter));  | 
|                 xml.AppendLine(string.Format(@"  | 
|     </{0}>",  | 
|                     /*{0}*/ item.ItemType));  | 
|             }  | 
|             Parameter[NewProject.FilterItems] = FormatParam(xml);  | 
|         }  | 
|   | 
|         // Matches empty lines; captures first newline  | 
|         static readonly Regex patternEmptyLines  | 
|             = new Regex(@"(?:^|(?<FIRST_NL>\r\n))(?:\r\n)+(?![\r\n]|$)|(?:\r\n)+$");  | 
|   | 
|         protected static string FormatParam(StringBuilder paramValue)  | 
|         {  | 
|             return FormatParam(paramValue.ToString());  | 
|         }  | 
|   | 
|         protected static string FormatParam(string paramValue)  | 
|         {  | 
|             // Remove empty lines; replace with first newline (if any)  | 
|             paramValue = patternEmptyLines.Replace(paramValue,  | 
|                 (Match m) => m.Groups["FIRST_NL"].Value);  | 
|   | 
|             return paramValue;  | 
|         }  | 
|     }  | 
| }  |