/**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt VS Add-in. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ using System; using System.IO; using System.Collections.Generic; using System.Windows.Forms; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.VCProjectEngine; using System.Text.RegularExpressions; using System.Net.Sockets; using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Collections; using Digia.Qt5ProjectLib; namespace Qt5VSAddin { class AddInEventHandler { private DTE dte; private EnvDTE.SolutionEvents solutionEvents; private EnvDTE.BuildEvents buildEvents; private EnvDTE.DocumentEvents documentEvents; private EnvDTE.ProjectItemsEvents projectItemsEvents; private EnvDTE.vsBuildAction currentBuildAction = vsBuildAction.vsBuildActionBuild; private VCProjectEngineEvents vcProjectEngineEvents = null; private CommandEvents debugStartEvents; private CommandEvents debugStartWithoutDebuggingEvents; private System.Threading.Thread appWrapperThread = null; private System.Diagnostics.Process appWrapperProcess = null; private bool terminateEditorThread = false; private TcpClient client = null; private byte[] qtAppWrapperHelloMessage = new byte[] { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; private SimpleThreadMessenger simpleThreadMessenger = null; private int dispId_VCFileConfiguration_ExcludedFromBuild; private int dispId_VCCLCompilerTool_UsePrecompiledHeader; private int dispId_VCCLCompilerTool_PrecompiledHeaderThrough; private int dispId_VCCLCompilerTool_PreprocessorDefinitions; private int dispId_VCCLCompilerTool_AdditionalIncludeDirectories; public AddInEventHandler(DTE _dte) { simpleThreadMessenger = new SimpleThreadMessenger(this); dte = _dte; Events2 events = dte.Events as Events2; buildEvents = (EnvDTE.BuildEvents)events.BuildEvents; buildEvents.OnBuildBegin += new _dispBuildEvents_OnBuildBeginEventHandler(buildEvents_OnBuildBegin); buildEvents.OnBuildProjConfigBegin += new _dispBuildEvents_OnBuildProjConfigBeginEventHandler(this.OnBuildProjConfigBegin); buildEvents.OnBuildDone += new _dispBuildEvents_OnBuildDoneEventHandler(this.buildEvents_OnBuildDone); documentEvents = (EnvDTE.DocumentEvents)events.get_DocumentEvents(null); documentEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(this.DocumentSaved); projectItemsEvents = (ProjectItemsEvents)events.ProjectItemsEvents; projectItemsEvents.ItemAdded += new _dispProjectItemsEvents_ItemAddedEventHandler(this.ProjectItemsEvents_ItemAdded); projectItemsEvents.ItemRemoved += new _dispProjectItemsEvents_ItemRemovedEventHandler(this.ProjectItemsEvents_ItemRemoved); projectItemsEvents.ItemRenamed += new _dispProjectItemsEvents_ItemRenamedEventHandler(this.ProjectItemsEvents_ItemRenamed); solutionEvents = (SolutionEvents)events.SolutionEvents; solutionEvents.ProjectAdded += new _dispSolutionEvents_ProjectAddedEventHandler(this.SolutionEvents_ProjectAdded); solutionEvents.ProjectRemoved += new _dispSolutionEvents_ProjectRemovedEventHandler(this.SolutionEvents_ProjectRemoved); solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(SolutionEvents_Opened); solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(SolutionEvents_AfterClosing); const string debugCommandsGUID = "{5EFC7975-14BC-11CF-9B2B-00AA00573819}"; debugStartEvents = events.get_CommandEvents(debugCommandsGUID, 295); debugStartEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(debugStartEvents_BeforeExecute); debugStartWithoutDebuggingEvents = events.get_CommandEvents(debugCommandsGUID, 368); debugStartWithoutDebuggingEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(debugStartWithoutDebuggingEvents_BeforeExecute); dispId_VCFileConfiguration_ExcludedFromBuild = GetPropertyDispId(typeof(VCFileConfiguration), "ExcludedFromBuild"); dispId_VCCLCompilerTool_UsePrecompiledHeader = GetPropertyDispId(typeof(VCCLCompilerTool), "UsePrecompiledHeader"); dispId_VCCLCompilerTool_PrecompiledHeaderThrough = GetPropertyDispId(typeof(VCCLCompilerTool), "PrecompiledHeaderThrough"); dispId_VCCLCompilerTool_PreprocessorDefinitions = GetPropertyDispId(typeof(VCCLCompilerTool), "PreprocessorDefinitions"); dispId_VCCLCompilerTool_AdditionalIncludeDirectories = GetPropertyDispId(typeof(VCCLCompilerTool), "AdditionalIncludeDirectories"); RegisterVCProjectEngineEvents(); if (Connect.Instance().AppWrapperPath == null) { Messages.DisplayCriticalErrorMessage("QtAppWrapper can't be found in the installation directory."); } else { appWrapperProcess = new System.Diagnostics.Process(); appWrapperProcess.StartInfo.FileName = Connect.Instance().AppWrapperPath; } appWrapperThread = new System.Threading.Thread(new System.Threading.ThreadStart(ListenForRequests)); appWrapperThread.Name = "QtAppWrapperListener"; appWrapperThread.Start(); } void debugStartEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault) { EnvDTE.Project selectedProject = HelperFunctions.GetSelectedQtProject(dte); if (selectedProject != null) { QtProject qtProject = QtProject.Create(selectedProject); if (qtProject != null) qtProject.SetQtEnvironment(); } } void debugStartWithoutDebuggingEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault) { EnvDTE.Project selectedProject = HelperFunctions.GetSelectedQtProject(dte); if (selectedProject != null) { QtProject qtProject = QtProject.Create(selectedProject); if (qtProject != null) qtProject.SetQtEnvironment(); } } private void OpenFileExternally(string fileName) { bool abortOperation; CheckoutFileIfNeeded(fileName, out abortOperation); if (abortOperation) return; string lowerCaseFileName = fileName.ToLower(); if (lowerCaseFileName.EndsWith(".ui")) { Connect.extLoader.loadDesigner(fileName); // Designer can't cope with many files in a short time. System.Threading.Thread.Sleep(1000); } else if (lowerCaseFileName.EndsWith(".ts")) { ExtLoader.loadLinguist(fileName); } #if false // QRC files are directly opened, using the QRC editor. else if (lowerCaseFileName.EndsWith(".qrc")) { Connect.extLoader.loadQrcEditor(fileName); } #endif } #if DEBUG private void setDirectory(string dir, string value) { foreach (EnvDTE.Project project in HelperFunctions.ProjectsInSolution(dte)) { VCProject vcProject = project.Object as VCProject; if (vcProject == null || vcProject.Files == null) continue; QtProject qtProject = QtProject.Create(project); if (qtProject == null) continue; if (dir == "MocDir") { string oldMocDir = QtVSIPSettings.GetMocDirectory(project); QtVSIPSettings.SaveMocDirectory(project, value); qtProject.UpdateMocSteps(oldMocDir); } else if (dir == "RccDir") { string oldRccDir = QtVSIPSettings.GetRccDirectory(project); QtVSIPSettings.SaveRccDirectory(project, value); qtProject.RefreshRccSteps(oldRccDir); } else if (dir == "UicDir") { string oldUicDir = QtVSIPSettings.GetUicDirectory(project); QtVSIPSettings.SaveUicDirectory(project, value); qtProject.UpdateUicSteps(oldUicDir, true); } } } #endif private void OnQRCFileSaved(string fileName) { foreach (EnvDTE.Project project in HelperFunctions.ProjectsInSolution(dte)) { VCProject vcProject = project.Object as VCProject; if (vcProject == null || vcProject.Files == null) continue; VCFile vcFile = (VCFile)((IVCCollection)vcProject.Files).Item(fileName); if (vcFile == null) continue; QtProject qtProject = QtProject.Create(project); qtProject.UpdateRccStep(vcFile, null); } } private void CheckoutFileIfNeeded(string fileName, out bool abortOperation) { abortOperation = false; if (QtVSIPSettings.GetDisableCheckoutFiles()) return; SourceControl sourceControl = dte.SourceControl; if (sourceControl == null) return; if (!sourceControl.IsItemUnderSCC(fileName)) return; if (sourceControl.IsItemCheckedOut(fileName)) return; if (QtVSIPSettings.GetAskBeforeCheckoutFile()) { string shortFileName = System.IO.Path.GetFileName(fileName); DialogResult dr = MessageBox.Show( SR.GetString("QuestionSCCCheckoutOnOpen", shortFileName), Resources.msgBoxCaption, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (dr == DialogResult.Cancel) abortOperation = true; if (dr != DialogResult.Yes) return; } sourceControl.CheckOutItem(fileName); } /// /// Dumb control to send stuff from one thread to another. /// private class SimpleThreadMessenger : Control { private AddInEventHandler addinEventHandler = null; public SimpleThreadMessenger(AddInEventHandler handler) { addinEventHandler = handler; CreateControl(); } public delegate void HandleMessageFromQtAppWrapperDelegate(string message); /// /// This function handle file names in the Addin's main thread, /// that come from the QtAppWrapper. /// public void HandleMessageFromQtAppWrapper(string message) { if (message.ToLower().EndsWith(".qrc")) addinEventHandler.OnQRCFileSaved(message); #if DEBUG else if (message.StartsWith("Autotests:set")) { // Messageformat from Autotests is Autotests:set: // where dir is MocDir, RccDir or UicDir //remove Autotests:set message = message.Substring(13); string dir = message.Remove(6); string value = message.Substring(7); addinEventHandler.setDirectory(dir, value); } #endif else addinEventHandler.OpenFileExternally(message); } } private void ListenForRequests() { if (appWrapperProcess == null) return; SimpleThreadMessenger.HandleMessageFromQtAppWrapperDelegate handleMessageFromQtAppWrapperDelegate; handleMessageFromQtAppWrapperDelegate = new SimpleThreadMessenger.HandleMessageFromQtAppWrapperDelegate(simpleThreadMessenger.HandleMessageFromQtAppWrapper); bool firstIteration = true; while (!terminateEditorThread) { try { if (!firstIteration) { if (appWrapperProcess.HasExited) appWrapperProcess.Close(); } else { firstIteration = false; } } catch { } appWrapperProcess.Start(); client = new TcpClient(); int connectionAttempts = 0; int appwrapperPort = 12015; while (!client.Connected && !terminateEditorThread && connectionAttempts < 10) { try { client.Connect(IPAddress.Loopback, appwrapperPort); if (!client.Connected) { ++connectionAttempts; System.Threading.Thread.Sleep(1000); } } catch { ++connectionAttempts; System.Threading.Thread.Sleep(1000); } } if (connectionAttempts >= 10) { Messages.DisplayErrorMessage(SR.GetString("CouldNotConnectToAppwrapper", appwrapperPort)); terminateEditorThread = true; } if (terminateEditorThread) { TerminateClient(); return; } NetworkStream clientStream = client.GetStream(); // say hello to qtappwrapper clientStream.Write(qtAppWrapperHelloMessage, 0, qtAppWrapperHelloMessage.Length); clientStream.Flush(); byte[] message = new byte[4096]; int bytesRead; while (!terminateEditorThread) { try { bytesRead = 0; try { //blocks until a client sends a message bytesRead = clientStream.Read(message, 0, 4096); } catch { // A socket error has occured, probably because // the QtAppWrapper has been terminated. // Break and then try to restart the QtAppWrapper. break; } if (bytesRead == 0) { //the client has disconnected from the server break; } //message has successfully been received UnicodeEncoding encoder = new UnicodeEncoding(); string fullMessageString = encoder.GetString(message, 0, bytesRead); string[] messages = fullMessageString.Split(new Char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string messageString in messages) { int index = messageString.IndexOf(' '); int requestedPid = Convert.ToInt32(messageString.Substring(0, index)); int currentPid = System.Diagnostics.Process.GetCurrentProcess().Id; if (requestedPid == currentPid) { // Actual file opening is done in the main thread. string file = messageString.Substring(index + 1); simpleThreadMessenger.Invoke(handleMessageFromQtAppWrapperDelegate, new object[] { file }); } } } catch (System.Threading.ThreadAbortException) { break; } catch { } } TerminateClient(); } } private void TerminateClient() { try { if (client != null && client.Connected) { NetworkStream stream = client.GetStream(); if (stream != null) stream.Close(); client.Close(); client = null; } } catch { /* ignore */ } } public void Disconnect() { if (buildEvents != null) { buildEvents.OnBuildBegin -= new _dispBuildEvents_OnBuildBeginEventHandler(this.buildEvents_OnBuildBegin); buildEvents.OnBuildProjConfigBegin -= new _dispBuildEvents_OnBuildProjConfigBeginEventHandler(this.OnBuildProjConfigBegin); buildEvents.OnBuildDone -= new _dispBuildEvents_OnBuildDoneEventHandler(this.buildEvents_OnBuildDone); } if (documentEvents != null) documentEvents.DocumentSaved -= new _dispDocumentEvents_DocumentSavedEventHandler(this.DocumentSaved); if (projectItemsEvents != null) { projectItemsEvents.ItemAdded -= new _dispProjectItemsEvents_ItemAddedEventHandler(this.ProjectItemsEvents_ItemAdded); projectItemsEvents.ItemRemoved -= new _dispProjectItemsEvents_ItemRemovedEventHandler(this.ProjectItemsEvents_ItemRemoved); projectItemsEvents.ItemRenamed -= new _dispProjectItemsEvents_ItemRenamedEventHandler(this.ProjectItemsEvents_ItemRenamed); } if (solutionEvents != null) { solutionEvents.ProjectAdded -= new _dispSolutionEvents_ProjectAddedEventHandler(this.SolutionEvents_ProjectAdded); solutionEvents.ProjectRemoved -= new _dispSolutionEvents_ProjectRemovedEventHandler(SolutionEvents_ProjectRemoved); solutionEvents.Opened -= new _dispSolutionEvents_OpenedEventHandler(SolutionEvents_Opened); solutionEvents.AfterClosing -= new _dispSolutionEvents_AfterClosingEventHandler(SolutionEvents_AfterClosing); } if (debugStartEvents != null) debugStartEvents.BeforeExecute -= new _dispCommandEvents_BeforeExecuteEventHandler(debugStartEvents_BeforeExecute); if (debugStartWithoutDebuggingEvents != null) debugStartWithoutDebuggingEvents.BeforeExecute -= new _dispCommandEvents_BeforeExecuteEventHandler(debugStartWithoutDebuggingEvents_BeforeExecute); if (vcProjectEngineEvents != null) vcProjectEngineEvents.ItemPropertyChange -= new _dispVCProjectEngineEvents_ItemPropertyChangeEventHandler(OnVCProjectEngineItemPropertyChange); if (appWrapperThread != null) { terminateEditorThread = true; if (appWrapperThread.IsAlive) { TerminateClient(); if (!appWrapperThread.Join(1000)) appWrapperThread.Abort(); } } } public void OnBuildProjConfigBegin(string projectName, string projectConfig, string platform, string solutionConfig) { if (currentBuildAction != vsBuildAction.vsBuildActionBuild && currentBuildAction != vsBuildAction.vsBuildActionRebuildAll) { return; // Don't do anything, if we're not building. } EnvDTE.Project project = null; foreach (EnvDTE.Project p in HelperFunctions.ProjectsInSolution(dte)) { if (p.UniqueName == projectName) { project = p; break; } } if (project == null || !HelperFunctions.IsQtProject(project)) return; QtProject qtpro = QtProject.Create(project); QtVersionManager versionManager = QtVersionManager.The(); string qtVersion = versionManager.GetProjectQtVersion(project, platform); if (qtVersion == null) { Messages.DisplayCriticalErrorMessage(SR.GetString("ProjectQtVersionNotFoundError", platform)); dte.ExecuteCommand("Build.Cancel", ""); return; } if (!QtVSIPSettings.GetDisableAutoMocStepsUpdate()) { if (qtpro.ConfigurationRowNamesChanged) { qtpro.UpdateMocSteps(QtVSIPSettings.GetMocDirectory(project)); } } // Solution config is given to function to get QTDIR property // set correctly also during batch build qtpro.SetQtEnvironment(qtVersion, solutionConfig); if (QtVSIPSettings.GetLUpdateOnBuild(project)) Translation.RunlUpdate(project); } void buildEvents_OnBuildBegin(vsBuildScope Scope, vsBuildAction Action) { currentBuildAction = Action; } public void buildEvents_OnBuildDone(vsBuildScope Scope, vsBuildAction Action) { } public void DocumentSaved(EnvDTE.Document document) { QtProject qtPro = QtProject.Create(document.ProjectItem.ContainingProject); if (!HelperFunctions.IsQtProject(qtPro.VCProject)) return; VCFile file = (VCFile)((IVCCollection)qtPro.VCProject.Files).Item(document.FullName); if (file.Extension == ".ui") { if (QtVSIPSettings.AutoUpdateUicSteps() && !QtProject.HasUicStep(file)) qtPro.AddUic4BuildStep(file); return; } if (!HelperFunctions.HasSourceFileExtension(file.Name) && !HelperFunctions.HasHeaderFileExtension(file.Name)) return; if (HelperFunctions.HasQObjectDeclaration(file)) { if (!qtPro.HasMocStep(file)) qtPro.AddMocStep(file); } else { qtPro.RemoveMocStep(file); } if (HelperFunctions.HasSourceFileExtension(file.Name)) { string moccedFileName = "moc_" + file.Name; if (qtPro.IsMoccedFileIncluded(file)) { // exclude moc_foo.cpp from build #if (VS2012 || VS2013) // Code copied here from 'GetFilesFromProject' // For some reason error CS1771 was generated from function call List tmpList = new System.Collections.Generic.List(); moccedFileName = HelperFunctions.NormalizeRelativeFilePath(moccedFileName); FileInfo fi = new FileInfo(moccedFileName); foreach (VCFile f in (IVCCollection)qtPro.VCProject.Files) { if (f.Name.ToLower() == fi.Name.ToLower()) tmpList.Add(f); } foreach (VCFile moccedFile in tmpList) QtProject.ExcludeFromAllBuilds(moccedFile); #else foreach (VCFile moccedFile in qtPro.GetFilesFromProject(moccedFileName)) QtProject.ExcludeFromAllBuilds(moccedFile); #endif } else { // make sure that moc_foo.cpp isn't excluded from build #if (VS2012 || VS2013) // Code copied here from 'GetFilesFromProject' // For some reason error CS1771 was generated from function call List moccedFiles = new System.Collections.Generic.List(); moccedFileName = HelperFunctions.NormalizeRelativeFilePath(moccedFileName); FileInfo fi = new FileInfo(moccedFileName); foreach (VCFile f in (IVCCollection)qtPro.VCProject.Files) { if (f.Name.ToLower() == fi.Name.ToLower()) moccedFiles.Add(f); } #else List moccedFiles = qtPro.GetFilesFromProject(moccedFileName); #endif if (moccedFiles.Count > 0) { bool hasDifferentMocFilesPerConfig = QtVSIPSettings.HasDifferentMocFilePerConfig(qtPro.Project); bool hasDifferentMocFilesPerPlatform = QtVSIPSettings.HasDifferentMocFilePerPlatform(qtPro.Project); VCFilter generatedFiles = qtPro.FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier); foreach (VCFile fileInFilter in (IVCCollection)generatedFiles.Files) { if (fileInFilter.Name == moccedFileName) { foreach (VCFileConfiguration config in (IVCCollection)fileInFilter.FileConfigurations) { bool exclude = true; VCConfiguration vcConfig = config.ProjectConfiguration as VCConfiguration; if (hasDifferentMocFilesPerConfig && hasDifferentMocFilesPerPlatform) { VCPlatform platform = vcConfig.Platform as VCPlatform; string platformName = platform.Name; if (fileInFilter.RelativePath.ToLower().Contains(vcConfig.ConfigurationName.ToLower()) && fileInFilter.RelativePath.ToLower().Contains(platform.Name.ToLower())) exclude = false; } else if (hasDifferentMocFilesPerConfig) { if (fileInFilter.RelativePath.ToLower().Contains(vcConfig.ConfigurationName.ToLower())) exclude = false; } else if (hasDifferentMocFilesPerPlatform) { VCPlatform platform = vcConfig.Platform as VCPlatform; string platformName = platform.Name; if (fileInFilter.RelativePath.ToLower().Contains(platformName.ToLower())) exclude = false; } else { exclude = false; } if (config.ExcludedFromBuild != exclude) config.ExcludedFromBuild = exclude; } } } foreach (VCFilter filt in (IVCCollection)generatedFiles.Filters) { foreach (VCFile f in (IVCCollection)filt.Files) { if (f.Name == moccedFileName) { foreach (VCFileConfiguration config in (IVCCollection)f.FileConfigurations) { VCConfiguration vcConfig = config.ProjectConfiguration as VCConfiguration; string filterToLookFor = ""; if (hasDifferentMocFilesPerConfig) filterToLookFor = vcConfig.ConfigurationName; if (hasDifferentMocFilesPerPlatform) { VCPlatform platform = vcConfig.Platform as VCPlatform; if (!string.IsNullOrEmpty(filterToLookFor)) filterToLookFor += '_'; filterToLookFor += platform.Name; } if (filt.Name == filterToLookFor) { if (config.ExcludedFromBuild) config.ExcludedFromBuild = false; } else { if (!config.ExcludedFromBuild) config.ExcludedFromBuild = true; } } } } } } } } } public void ProjectItemsEvents_ItemAdded(ProjectItem projectItem) { Project project = HelperFunctions.GetSelectedQtProject(Connect._applicationObject); QtProject qtPro = QtProject.Create(project); if (!HelperFunctions.IsQtProject(project)) return; VCFilter filter = null; VCFile vcFile = GetVCFileFromProject(projectItem.Name, qtPro.VCProject); if (vcFile == null) return; try { // Try to find the filter, the file is located in // If the file is not inside any filter, move it to // the according one, used by the Add-in filter = (VCFilter)vcFile.Parent; } catch { } try { FakeFilter ui = Filters.FormFiles(); FakeFilter qrc = Filters.ResourceFiles(); FakeFilter ts = Filters.TranslationFiles(); FakeFilter h = Filters.HeaderFiles(); FakeFilter src = Filters.SourceFiles(); VCFilter uiFilter = qtPro.FindFilterFromGuid(ui.UniqueIdentifier); VCFilter tsFilter = qtPro.FindFilterFromGuid(ts.UniqueIdentifier); VCFilter qrcFilter = qtPro.FindFilterFromGuid(qrc.UniqueIdentifier); VCFilter hFilter = qtPro.FindFilterFromGuid(h.UniqueIdentifier); VCFilter srcFilter = qtPro.FindFilterFromGuid(src.UniqueIdentifier); if (HelperFunctions.HasSourceFileExtension(vcFile.Name)) { if (vcFile.Name.ToLower().StartsWith("moc_")) return; else if (vcFile.Name.ToLower().StartsWith("qrc_")) { // Do not use precompiled headers with these files QtProject.SetPCHOption(vcFile, pchOption.pchNone); return; } string pcHeaderThrough = qtPro.GetPrecompiledHeaderThrough(); if (pcHeaderThrough != null) { string pcHeaderCreator = pcHeaderThrough.Remove(pcHeaderThrough.LastIndexOf('.')) + ".cpp"; if (vcFile.Name.ToLower().EndsWith(pcHeaderCreator.ToLower()) && HelperFunctions.CxxFileContainsNotCommented(vcFile, "#include \"" + pcHeaderThrough + "\"", false, false)) { //File is used to create precompiled headers QtProject.SetPCHOption(vcFile, pchOption.pchCreateUsingSpecific); return; } } if (filter == null && !HelperFunctions.IsInFilter(vcFile, src)) { if (null == srcFilter && qtPro.VCProject.CanAddFilter(src.Name)) { srcFilter = (VCFilter)qtPro.VCProject.AddFilter(src.Name); srcFilter.Filter = src.Filter; srcFilter.ParseFiles = src.ParseFiles; srcFilter.UniqueIdentifier = src.UniqueIdentifier; } qtPro.RemoveItem(projectItem); qtPro.AddFileToProject(vcFile.FullPath, src); } if (HelperFunctions.HasQObjectDeclaration(vcFile)) { #if (VS2010 || VS2012 || VS2013) HelperFunctions.EnsureCustomBuildToolAvailable(projectItem); #endif qtPro.AddMocStep(vcFile); } } else if (HelperFunctions.HasHeaderFileExtension(vcFile.Name)) { if (vcFile.Name.ToLower().StartsWith("ui_")) return; if (filter == null && !HelperFunctions.IsInFilter(vcFile, h)) { if (null == hFilter && qtPro.VCProject.CanAddFilter(h.Name)) { hFilter = (VCFilter)qtPro.VCProject.AddFilter(h.Name); hFilter.Filter = h.Filter; hFilter.ParseFiles = h.ParseFiles; hFilter.UniqueIdentifier = h.UniqueIdentifier; } qtPro.RemoveItem(projectItem); qtPro.AddFileToProject(vcFile.FullPath, h); } if (HelperFunctions.HasQObjectDeclaration(vcFile)) { #if (VS2010 || VS2012 || VS2013) HelperFunctions.EnsureCustomBuildToolAvailable(projectItem); #endif qtPro.AddMocStep(vcFile); } } else if (vcFile.Name.EndsWith(".ui")) { if (filter == null && !HelperFunctions.IsInFilter(vcFile, ui)) { if (null == uiFilter && qtPro.VCProject.CanAddFilter(ui.Name)) { uiFilter = (VCFilter)qtPro.VCProject.AddFilter(ui.Name); uiFilter.Filter = ui.Filter; uiFilter.ParseFiles = ui.ParseFiles; uiFilter.UniqueIdentifier = ui.UniqueIdentifier; } qtPro.RemoveItem(projectItem); qtPro.AddFileToProject(vcFile.FullPath, ui); } #if (VS2010 || VS2012 || VS2013) HelperFunctions.EnsureCustomBuildToolAvailable(projectItem); #endif qtPro.AddUic4BuildStep(vcFile); } else if (vcFile.Name.EndsWith(".qrc")) { if (filter == null && !HelperFunctions.IsInFilter(vcFile, qrc)) { if (null == qrcFilter && qtPro.VCProject.CanAddFilter(qrc.Name)) { qrcFilter = (VCFilter)qtPro.VCProject.AddFilter(qrc.Name); qrcFilter.Filter = qrc.Filter; qrcFilter.ParseFiles = qrc.ParseFiles; qrcFilter.UniqueIdentifier = qrc.UniqueIdentifier; } qtPro.RemoveItem(projectItem); qtPro.AddFileToProject(vcFile.FullPath, qrc); } #if (VS2010 || VS2012 || VS2013) HelperFunctions.EnsureCustomBuildToolAvailable(projectItem); #endif qtPro.UpdateRccStep(vcFile, null); } else if (HelperFunctions.IsTranslationFile(vcFile)) { if (filter == null && !HelperFunctions.IsInFilter(vcFile, ts)) { if (null == tsFilter && qtPro.VCProject.CanAddFilter(ts.Name)) { tsFilter = (VCFilter)qtPro.VCProject.AddFilter(ts.Name); tsFilter.Filter = ts.Filter; tsFilter.ParseFiles = ts.ParseFiles; tsFilter.UniqueIdentifier = ts.UniqueIdentifier; } qtPro.RemoveItem(projectItem); qtPro.AddFileToProject(vcFile.FullPath, ts); } } } catch { } return; } void ProjectItemsEvents_ItemRemoved(ProjectItem ProjectItem) { Project pro = HelperFunctions.GetSelectedQtProject(Connect._applicationObject); if (pro == null) return; QtProject qtPro = QtProject.Create(pro); qtPro.RemoveGeneratedFiles(ProjectItem.Name); } void ProjectItemsEvents_ItemRenamed(ProjectItem ProjectItem, string OldName) { if (OldName == null) return; Project pro = HelperFunctions.GetSelectedQtProject(Connect._applicationObject); if (pro == null) return; QtProject qtPro = QtProject.Create(pro); qtPro.RemoveGeneratedFiles(OldName); ProjectItemsEvents_ItemAdded(ProjectItem); } void SolutionEvents_ProjectAdded(Project project) { if (HelperFunctions.IsQMakeProject(project)) { RegisterVCProjectEngineEvents(project); VCProject vcpro = project.Object as VCProject; VCFilter filter = null; foreach (VCFilter f in vcpro.Filters as IVCCollection) if (f.Name == Filters.HeaderFiles().Name) { filter = f; break; } if (filter != null) { foreach (VCFile file in filter.Files as IVCCollection) { foreach (VCFileConfiguration config in file.FileConfigurations as IVCCollection) { VCCustomBuildTool tool = HelperFunctions.GetCustomBuildTool(config); if (tool != null && tool.CommandLine != null && tool.CommandLine.Contains("moc.exe")) { Regex reg = new Regex("[^ ^\n]+moc\\.exe"); MatchCollection matches = reg.Matches(tool.CommandLine); string qtDir = null; if (matches.Count != 1) { QtVersionManager vm = QtVersionManager.The(); qtDir = vm.GetInstallPath(vm.GetDefaultVersion()); } else { qtDir = matches[0].ToString(); qtDir = qtDir.Remove(qtDir.LastIndexOf("\\")); qtDir = qtDir.Remove(qtDir.LastIndexOf("\\")); } qtDir = qtDir.Replace("_(QTDIR)", "$(QTDIR)"); HelperFunctions.SetDebuggingEnvironment(project, "PATH=" + qtDir + "\\bin;$(PATH)", true); } } } } } } void SolutionEvents_ProjectRemoved(Project project) { } void SolutionEvents_Opened() { foreach (Project p in HelperFunctions.ProjectsInSolution(Connect._applicationObject)) { if (HelperFunctions.IsQtProject(p)) { RegisterVCProjectEngineEvents(p); } } } void SolutionEvents_AfterClosing() { QtProject.ClearInstances(); } /// /// Tries to get a VCProjectEngine from the loaded projects and registers the handlers for VCProjectEngineEvents. /// void RegisterVCProjectEngineEvents() { foreach (EnvDTE.Project project in HelperFunctions.ProjectsInSolution(dte)) if (project != null && HelperFunctions.IsQtProject(project)) RegisterVCProjectEngineEvents(project); } /// /// Retrieves the VCProjectEngine from the given project and registers the handlers for VCProjectEngineEvents. /// void RegisterVCProjectEngineEvents(Project p) { if (vcProjectEngineEvents != null) return; VCProject vcPrj = p.Object as VCProject; VCProjectEngine prjEngine = vcPrj.VCProjectEngine as VCProjectEngine; if (prjEngine != null) { vcProjectEngineEvents = prjEngine.Events as VCProjectEngineEvents; if (vcProjectEngineEvents != null) { try { vcProjectEngineEvents.ItemPropertyChange += new _dispVCProjectEngineEvents_ItemPropertyChangeEventHandler(OnVCProjectEngineItemPropertyChange); } catch { Messages.DisplayErrorMessage("VCProjectEngine events could not be registered."); } } } } private void OnVCProjectEngineItemPropertyChange(object item, object tool, int dispid) { //System.Diagnostics.Debug.WriteLine("OnVCProjectEngineItemPropertyChange " + dispid.ToString()); VCFileConfiguration vcFileCfg = item as VCFileConfiguration; if (vcFileCfg == null) { // A global or project specific property has changed. VCConfiguration vcCfg = item as VCConfiguration; if (vcCfg == null) return; VCProject vcPrj = vcCfg.project as VCProject; if (vcPrj == null) return; if (!HelperFunctions.IsQtProject(vcPrj)) return; if (dispid == dispId_VCCLCompilerTool_UsePrecompiledHeader || dispid == dispId_VCCLCompilerTool_PrecompiledHeaderThrough || dispid == dispId_VCCLCompilerTool_AdditionalIncludeDirectories || dispid == dispId_VCCLCompilerTool_PreprocessorDefinitions) { QtProject qtPrj = QtProject.Create(vcPrj); qtPrj.RefreshMocSteps(); } } else { // A file specific property has changed. VCFile vcFile = vcFileCfg.File as VCFile; if (vcFile == null) return; VCProject vcPrj = vcFile.project as VCProject; if (vcPrj == null) return; if (!HelperFunctions.IsQtProject(vcPrj)) return; if (dispid == dispId_VCFileConfiguration_ExcludedFromBuild) { QtProject qtPrj = QtProject.Create(vcPrj); qtPrj.OnExcludedFromBuildChanged(vcFile, vcFileCfg); } else if (dispid == dispId_VCCLCompilerTool_UsePrecompiledHeader || dispid == dispId_VCCLCompilerTool_PrecompiledHeaderThrough || dispid == dispId_VCCLCompilerTool_AdditionalIncludeDirectories || dispid == dispId_VCCLCompilerTool_PreprocessorDefinitions) { QtProject qtPrj = QtProject.Create(vcPrj); qtPrj.RefreshMocStep(vcFile); } } } private static VCFile GetVCFileFromProject(string absFileName, VCProject project) { foreach (VCFile f in (IVCCollection)project.Files) { if (f.Name.ToLower() == absFileName.ToLower()) return f; } return null; } /// /// Returns the COM DISPID of the given property. /// private static int GetPropertyDispId(Type type, string propertyName) { System.Reflection.PropertyInfo pi = type.GetProperty(propertyName); if (pi != null) { foreach (Attribute attribute in pi.GetCustomAttributes(true)) { DispIdAttribute dispIdAttribute = attribute as DispIdAttribute; if (dispIdAttribute != null) { return dispIdAttribute.Value; } } } return 0; } } }