/**************************************************************************** ** ** Copyright (C) 2016 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 Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TemplateWizard; using QtVsTools.Core; using QtVsTools.VisualStudio; using System.Collections.Generic; using System.IO; using System.Linq; namespace QtVsTools.Wizards.ClassWizard { public class GuiClassWizard : IClassWizard { public WizardResult Run(EnvDTE.DTE dte, string name, string location) { var serviceProvider = new ServiceProvider(dte as IServiceProvider); var iVsUIShell = VsServiceProvider.GetService(); iVsUIShell.EnableModeless(0); try { System.IntPtr hwnd; iVsUIShell.GetDialogOwnerHwnd(out hwnd); try { if (string.IsNullOrEmpty(name)) name = @"QtWidgetsClass"; data.ClassName = name; data.BaseClass = @"QWidget"; data.ClassHeaderFile = name + @".h"; data.ClassSourceFile = name + @".cpp"; data.UiFile = data.ClassName + @".ui"; var wizard = new WizardWindow(new List { new WizardIntroPage { Data = data, Header = @"Welcome to the Qt Widgets Class Wizard", Message = @"This wizard will add a new Qt Widgets class to your project. " + @"The wizard creates a .h and .cpp file. It also creates a new " + @"empty form." + System.Environment.NewLine + System.Environment.NewLine + "To continue, click Next.", PreviousButtonEnabled = false, NextButtonEnabled = true, FinishButtonEnabled = false, CancelButtonEnabled = true }, new GuiClassPage { Data = data, Header = @"Welcome to the Qt Widgets Class Wizard", Message = @"This wizard will add a new Qt Widgets class to your project. " + @"The wizard creates a .h and .cpp file. It also creates a new " + @"empty form.", PreviousButtonEnabled = true, NextButtonEnabled = false, FinishButtonEnabled = true, CancelButtonEnabled = true } }) { Title = @"Qt Widgets Class Wizard" }; WindowHelper.ShowModal(wizard, hwnd); if (!wizard.DialogResult.HasValue || !wizard.DialogResult.Value) throw new System.Exception("Unexpected wizard return value."); var array = data.ClassName.Split(new[] { "::" }, System .StringSplitOptions.RemoveEmptyEntries); data.ClassName = array.LastOrDefault(); string nsBegin = string.Empty, nsEnd = string.Empty; for (var i = 0; i < array.Length - 1; ++i) { nsBegin += "namespace " + array[i] + " {\r\n"; nsEnd = "} // namespace " + array[i] + "\r\n" + nsEnd; } var pro = HelperFunctions.GetSelectedQtProject(dte); if (pro == null) throw new QtVSException("Can't find a selected project"); var qtProject = QtProject.Create(pro); var hppFile = AddProjectItemHpp(location); ReplaceNamespaceToken(hppFile, nsBegin, nsEnd); qtProject.AdjustWhitespace(hppFile); qtProject.AddFileToProject(hppFile, Filters.HeaderFiles()); VsShellUtilities.OpenDocument(serviceProvider, hppFile); var pch = string.Empty; if (qtProject.UsesPrecompiledHeaders()) pch = qtProject.GetPrecompiledHeaderThrough(); var cppFile = AddProjectItemCpp(location, pch); ReplaceNamespaceToken(cppFile, nsBegin, nsEnd); qtProject.AdjustWhitespace(cppFile); qtProject.AddFileToProject(cppFile, Filters.SourceFiles()); VsShellUtilities.OpenDocument(serviceProvider, cppFile); var uiFile = AddProjectItemUi(location); qtProject.AdjustWhitespace(uiFile); qtProject.AddFileToProject(uiFile, Filters.FormFiles()); } catch (QtVSException exception) { Messages.DisplayErrorMessage(exception.Message); throw; // re-throw, but keep the original exception stack intact } } catch { throw new WizardBackoutException(); } finally { iVsUIShell.EnableModeless(1); } return WizardResult.Finished; } private readonly WizardData data = new WizardData { DefaultModules = new List { @"QtCore", @"QtGui", @"QtWidgets" } }; private const string MemberClassHeader = "#pragma once\r\n" + "\r\n" + "#include <%BASECLASS%>\r\n" + "#include \"%UI_HDR%\"\r\n" + "\r\n" + "%NAMESPACE_BEGIN%class %CLASS% : public %BASECLASS%\r\n" + "{\r\n" + " Q_OBJECT\r\n" + "\r\n" + "public:\r\n" + " %CLASS%(QWidget *parent = Q_NULLPTR);\r\n" + " ~%CLASS%();\r\n" + "\r\n" + "private:\r\n" + " Ui::%CLASS% ui;\r\n" + "};\r\n" + "%NAMESPACE_END%"; private const string MemberClassSource = "#include \"%INCLUDE%\"\r\n" + "\r\n" + "%NAMESPACE_BEGIN%%CLASS%::%CLASS%(QWidget *parent)\r\n" + " : %BASECLASS%(parent)\r\n" + "{\r\n" + " ui.setupUi(this);\r\n" + "}\r\n" + "\r\n" + "%CLASS%::~%CLASS%()\r\n" + "{\r\n" + "}\r\n" + "%NAMESPACE_END%"; private const string MemberPointerClassHeader = "#pragma once\r\n" + "\r\n" + "#include <%BASECLASS%>\r\n" + "namespace Ui { class %CLASS%; };\r\n" + "\r\n" + "%NAMESPACE_BEGIN%class %CLASS% : public %BASECLASS%\r\n" + "{\r\n" + " Q_OBJECT\r\n" + "\r\n" + "public:\r\n" + " %CLASS%(QWidget *parent = Q_NULLPTR);\r\n" + " ~%CLASS%();\r\n" + "\r\n" + "private:\r\n" + " Ui::%CLASS% *ui;\r\n" + "};\r\n" + "%NAMESPACE_END%"; private const string MemberPointerClassSource = "#include \"%INCLUDE%\"\r\n" + "#include \"%UI_HDR%\"\r\n" + "\r\n" + "%NAMESPACE_BEGIN%%CLASS%::%CLASS%(QWidget *parent)\r\n" + " : %BASECLASS%(parent)\r\n" + "{\r\n" + " ui = new Ui::%CLASS%();\r\n" + " ui->setupUi(this);\r\n" + "}\r\n" + "\r\n" + "%CLASS%::~%CLASS%()\r\n" + "{\r\n" + " delete ui;\r\n" + "}\r\n" + "%NAMESPACE_END%"; private const string InheritanceClassHeader = "#pragma once\r\n" + "\r\n" + "#include <%BASECLASS%>\r\n" + "#include \"%UI_HDR%\"\r\n" + "\r\n" + "%NAMESPACE_BEGIN%class %CLASS% : public %BASECLASS%, public Ui::%CLASS%\r\n" + "{\r\n" + " Q_OBJECT\r\n" + "\r\n" + "public:\r\n" + " %CLASS%(QWidget *parent = Q_NULLPTR);\r\n" + " ~%CLASS%();\r\n" + "};\r\n" + "%NAMESPACE_END%"; private const string InheritanceClassSource = "#include \"%INCLUDE%\"\r\n" + "\r\n" + "%NAMESPACE_BEGIN%%CLASS%::%CLASS%(QWidget *parent)\r\n" + " : %BASECLASS%(parent)\r\n" + "{\r\n" + " setupUi(this);\r\n" + "}\r\n" + "\r\n" + "%CLASS%::~%CLASS%()\r\n" + "{\r\n" + "}\r\n" + "%NAMESPACE_END%"; private static void ReplaceNamespaceToken(string file, string nsBegin, string nsEnd) { if (!string.IsNullOrEmpty(nsBegin)) nsBegin += System.Environment.NewLine; QtProject.ReplaceTokenInFile(file, "%NAMESPACE_BEGIN%", nsBegin); if (!string.IsNullOrEmpty(nsEnd)) nsEnd = System.Environment.NewLine + nsEnd; QtProject.ReplaceTokenInFile(file, "%NAMESPACE_END%", nsEnd); } private string AddProjectItemHpp(string location) { var replaceUiHeader = true; var hppFile = Path.GetTempFileName(); using (var tmp = new StreamWriter(hppFile)) { var content = string.Empty; switch (data.UiClassInclusion) { case UiClassInclusion.Member: content = MemberClassHeader; break; case UiClassInclusion.MemberPointer: replaceUiHeader = false; content = MemberPointerClassHeader; break; case UiClassInclusion.MultipleInheritance: content = InheritanceClassHeader; break; } tmp.Write(content); } hppFile = QtProject.CopyFileToFolder(hppFile, location, data.ClassHeaderFile); QtProject.ReplaceTokenInFile(hppFile, "%CLASS%", data.ClassName); QtProject.ReplaceTokenInFile(hppFile, "%BASECLASS%", data.BaseClass); if (replaceUiHeader) { QtProject.ReplaceTokenInFile(hppFile, "%UI_HDR%", "ui_" + Path .GetFileNameWithoutExtension(data.UiFile) + ".h"); } return hppFile; } private string AddProjectItemCpp(string location, string pch) { var replaceUiHeader = false; var cppFile = Path.GetTempFileName(); using (var tmp = new StreamWriter(cppFile)) { var content = string.Empty; switch (data.UiClassInclusion) { case UiClassInclusion.Member: content = MemberClassSource; break; case UiClassInclusion.MemberPointer: replaceUiHeader = true; content = MemberPointerClassSource; break; case UiClassInclusion.MultipleInheritance: content = InheritanceClassSource; break; } tmp.Write(content); } cppFile = QtProject.CopyFileToFolder(cppFile, location, data.ClassSourceFile); if (!string.IsNullOrEmpty(pch)) QtProject.ReplaceTokenInFile(cppFile, "%INCLUDE%", pch + "\"\r\n#include \"%INCLUDE%"); QtProject.ReplaceTokenInFile(cppFile, "%INCLUDE%", data.ClassHeaderFile); QtProject.ReplaceTokenInFile(cppFile, "%CLASS%", data.ClassName); QtProject.ReplaceTokenInFile(cppFile, "%BASECLASS%", data.BaseClass); if (replaceUiHeader) { QtProject.ReplaceTokenInFile(cppFile, "%UI_HDR%", "ui_" + Path .GetFileNameWithoutExtension(data.UiFile) + ".h"); } return cppFile; } private string AddProjectItemUi(string location) { var uiFile = Path.GetTempFileName(); using (var tmp = new StreamWriter(uiFile)) { tmp.Write( "\r\n" + " %CLASS%\r\n" + " \r\n" + " \r\n" + " %CLASS%\r\n" + " \r\n" + " \r\n" + " \r\n" + " 0\r\n" + " 0\r\n" + " 400\r\n" + " 300\r\n" + " \r\n" + " \r\n" + " \r\n" + " %CLASS%\r\n" + " %CENTRAL_WIDGET%\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + "\r\n"); } uiFile = QtProject.CopyFileToFolder(uiFile, location, data.UiFile); QtProject.ReplaceTokenInFile(uiFile, "%CLASS%", data.ClassName); QtProject.ReplaceTokenInFile(uiFile, "%BASECLASS%", data.BaseClass); if (data.BaseClass == "QMainWindow") { QtProject.ReplaceTokenInFile(uiFile, "%CENTRAL_WIDGET%", "\r\n " + "\r\n " + "\r\n " + "\r\n "); } else if (data.BaseClass == "QDockWidget") { QtProject.ReplaceTokenInFile(uiFile, "%CENTRAL_WIDGET%", "\r\n "); } else { QtProject.ReplaceTokenInFile(uiFile, "%CENTRAL_WIDGET%", string.Empty); } return uiFile; } } }