| /****************************************************************************  | 
| **  | 
| ** 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<SVsUIShell, IVsUIShell>();  | 
|   | 
|             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<WizardPage> {  | 
|                         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<string> {  | 
|                 @"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(  | 
|                     "<UI version=\"4.0\" >\r\n"  | 
|                     + " <class>%CLASS%</class>\r\n"  | 
|                     + " <widget class=\"%BASECLASS%\" name=\"%CLASS%\" >\r\n"  | 
|                     + "  <property name=\"objectName\" >\r\n"  | 
|                     + "   <string notr=\"true\">%CLASS%</string>\r\n"  | 
|                     + "  </property>\r\n"  | 
|                     + "  <property name=\"geometry\" >\r\n"  | 
|                     + "   <rect>\r\n"  | 
|                     + "    <x>0</x>\r\n"  | 
|                     + "    <y>0</y>\r\n"  | 
|                     + "    <width>400</width>\r\n"  | 
|                     + "    <height>300</height>\r\n"  | 
|                     + "   </rect>\r\n"  | 
|                     + "  </property>\r\n"  | 
|                     + "  <property name=\"windowTitle\" >\r\n"  | 
|                     + "   <string>%CLASS%</string>\r\n"  | 
|                     + "  </property>%CENTRAL_WIDGET%\r\n"  | 
|                     + " </widget>\r\n"  | 
|                     + " <layoutDefault spacing=\"6\" margin=\"11\" />\r\n"  | 
|                     + " <pixmapfunction></pixmapfunction>\r\n"  | 
|                     + " <resources/>\r\n"  | 
|                     + " <connections/>\r\n"  | 
|                     + "</UI>\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  <widget class=\"QMenuBar\" name=\"menuBar\" />"  | 
|                     + "\r\n  <widget class=\"QToolBar\" name=\"mainToolBar\" />"  | 
|                     + "\r\n  <widget class=\"QWidget\" name=\"centralWidget\" />"  | 
|                     + "\r\n  <widget class=\"QStatusBar\" name=\"statusBar\" />");  | 
|             } else if (data.BaseClass == "QDockWidget") {  | 
|                 QtProject.ReplaceTokenInFile(uiFile, "%CENTRAL_WIDGET%",  | 
|                     "\r\n  <widget class=\"QWidget\" name=\"widget\" />");  | 
|             } else {  | 
|                 QtProject.ReplaceTokenInFile(uiFile, "%CENTRAL_WIDGET%", string.Empty);  | 
|             }  | 
|   | 
|             return uiFile;  | 
|         }  | 
|     }  | 
| }  |