| /****************************************************************************  | 
| **  | 
| ** 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 CoreClassWizard : IClassWizard  | 
|     {  | 
|         public WizardResult Run(EnvDTE.DTE dte, string name, string location)  | 
|         {  | 
|             ThreadHelper.ThrowIfNotOnUIThread();  | 
|   | 
|             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 = @"QtClass";  | 
|   | 
|                     data.ClassName = name;  | 
|                     data.BaseClass = @"QObject";  | 
|                     data.ConstructorSignature = "QObject *parent";  | 
|                     data.InsertQObjectMacro = true;  | 
|                     data.ClassHeaderFile = name + @".h";  | 
|                     data.ClassSourceFile = name + @".cpp";  | 
|   | 
|                     var wizard = new WizardWindow(new List<WizardPage> {  | 
|                         new WizardIntroPage {  | 
|                             Data = data,  | 
|                             Header = @"Welcome to the Qt Class Wizard",  | 
|                             Message = @"This wizard will add a new Qt class to your project. The "  | 
|                                 + @"wizard creates a .h and .cpp file." + System.Environment.NewLine  | 
|                                 + System.Environment.NewLine + "To continue, click Next.",  | 
|                             PreviousButtonEnabled = false,  | 
|                             NextButtonEnabled = true,  | 
|                             FinishButtonEnabled = false,  | 
|                             CancelButtonEnabled = true  | 
|                         },  | 
|                         new CoreClassPage {  | 
|                             Data = data,  | 
|                             Header = @"Welcome to the Qt Class Wizard",  | 
|                             Message = @"This wizard will add a new Qt class to your project. The "  | 
|                                 + @"wizard creates a .h and .cpp file.",  | 
|                             PreviousButtonEnabled = true,  | 
|                             NextButtonEnabled = false,  | 
|                             FinishButtonEnabled = true,  | 
|                             CancelButtonEnabled = true  | 
|                         }  | 
|                     })  | 
|                     {  | 
|                         Title = @"Qt 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);  | 
|   | 
|                 } 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"  | 
|             }  | 
|         };  | 
|   | 
|         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 hppFile = Path.GetTempFileName();  | 
|             using (var tmp = new StreamWriter(hppFile)) {  | 
|                 tmp.Write("#pragma once\r\n\r\n"  | 
|                     + "%BASECLASSINCLUDE%%NAMESPACE_BEGIN%class %CLASS%%BASEDECL%\r\n"  | 
|                     + "{%Q_OBJECT%\r\n"  | 
|                     + "public:\r\n"  | 
|                     + "    %CLASS%(%CTORSIG%);\r\n"  | 
|                     + "    ~%CLASS%();\r\n"  | 
|                     + "};\r\n"  | 
|                     + "%NAMESPACE_END%");  | 
|             }  | 
|             hppFile = QtProject.CopyFileToFolder(hppFile, location, data.ClassHeaderFile);  | 
|   | 
|             QtProject.ReplaceTokenInFile(hppFile, "%CLASS%", data.ClassName);  | 
|             QtProject.ReplaceTokenInFile(hppFile, "%BASECLASS%", data.BaseClass);  | 
|   | 
|             if (string.IsNullOrEmpty(data.BaseClass)) {  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%BASEDECL%", string.Empty);  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%BASECLASSINCLUDE%", string.Empty);  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%Q_OBJECT%", string.Empty);  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%CTORSIG%", string.Empty);  | 
|             } else {  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%BASEDECL%", " : public "  | 
|                     + data.BaseClass);  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%BASECLASSINCLUDE%", "#include <"  | 
|                     + data.BaseClass + ">\r\n\r\n");  | 
|                 if (data.InsertQObjectMacro)  | 
|                     QtProject.ReplaceTokenInFile(hppFile, "%Q_OBJECT%", "\r\n\tQ_OBJECT\r\n");  | 
|                 QtProject.ReplaceTokenInFile(hppFile, "%CTORSIG%", data.ConstructorSignature);  | 
|             }  | 
|   | 
|             return hppFile;  | 
|         }  | 
|   | 
|         private string AddProjectItemCpp(string location, string pch)  | 
|         {  | 
|             var cppFile = Path.GetTempFileName();  | 
|             using (var tmp = new StreamWriter(cppFile)) {  | 
|                 tmp.Write("#include \"%INCLUDE%\"\r\n\r\n"  | 
|                     + "%NAMESPACE_BEGIN%%CLASS%::%CLASS%(%CTORSIG%)%BASECLASS%\r\n"  | 
|                     + "{\r\n}\r\n\r\n"  | 
|                     + "%CLASS%::~%CLASS%()\r\n"  | 
|                     + "{\r\n}\r\n"  | 
|                     + "%NAMESPACE_END%");  | 
|             }  | 
|             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%", string.IsNullOrEmpty(data  | 
|                 .ConstructorSignature) ? "" : "\r\n    : " + data.BaseClass + "(parent)");  | 
|             QtProject.ReplaceTokenInFile(cppFile, "%CTORSIG%", data.ConstructorSignature);  | 
|   | 
|             return cppFile;  | 
|         }  | 
|     }  | 
| }  |