Konstantin Koch 8287c54432 Included the Visual Studio extension and made the necessary changes to make it run.
Replaced the old VS templates with ones that offer more flexiblity.
Started replacing the Content Project for the samples with our custom project type.
Inlcuded a basic not yet working AssimpImporter.
2015-04-08 14:50:03 +02:00

250 lines
12 KiB
C#

/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, please send an email to
* vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.Project.Automation {
/// <summary>
/// Contains ProjectItem objects
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
[ComVisible(true)]
public class OAProjectItems : OANavigableProjectItems {
#region ctor
public OAProjectItems(OAProject project, HierarchyNode nodeWithItems)
: base(project, nodeWithItems) {
}
#endregion
#region EnvDTE.ProjectItems
/// <summary>
/// Creates a new project item from an existing directory and all files and subdirectories
/// contained within it.
/// </summary>
/// <param name="directory">The full path of the directory to add.</param>
/// <returns>A ProjectItem object.</returns>
public override ProjectItem AddFromDirectory(string directory) {
CheckProjectIsValid();
return UIThread.Instance.RunSync<EnvDTE.ProjectItem>(() => {
ProjectItem result = AddFolder(directory, null);
foreach (string subdirectory in Directory.EnumerateDirectories(directory)) {
result.ProjectItems.AddFromDirectory(Path.Combine(directory, subdirectory));
}
foreach (var extension in this.Project.ProjectNode.CodeFileExtensions) {
foreach (string filename in Directory.EnumerateFiles(directory, "*" + extension)) {
result.ProjectItems.AddFromFile(Path.Combine(directory, filename));
}
foreach (string filename in Directory.EnumerateFiles(directory, "*" + extension)) {
result.ProjectItems.AddFromFile(Path.Combine(directory, filename));
}
}
return result;
});
}
/// <summary>
/// Creates a new project item from an existing item template file and adds it to the project.
/// </summary>
/// <param name="fileName">The full path and file name of the template project file.</param>
/// <param name="name">The file name to use for the new project item.</param>
/// <returns>A ProjectItem object. </returns>
public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) {
CheckProjectIsValid();
ProjectNode proj = this.Project.ProjectNode;
EnvDTE.ProjectItem itemAdded = null;
using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) {
// Determine the operation based on the extension of the filename.
// We should run the wizard only if the extension is vstemplate
// otherwise it's a clone operation
VSADDITEMOPERATION op;
UIThread.Instance.RunSync(() => {
if (VsUtilities.IsTemplateFile(fileName)) {
op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD;
} else {
op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE;
}
VSADDRESULT[] result = new VSADDRESULT[1];
// It is not a very good idea to throw since the AddItem might return Cancel or Abort.
// The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash.
// The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22.
ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result));
string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems);
string templateFilePath = System.IO.Path.Combine(fileDirectory, name);
itemAdded = this.EvaluateAddResult(result[0], templateFilePath);
});
}
return itemAdded;
}
private void CheckProjectIsValid() {
if (this.Project == null || this.Project.ProjectNode == null || this.Project.ProjectNode.Site == null || this.Project.ProjectNode.IsClosed) {
throw new InvalidOperationException();
}
}
/// <summary>
/// Adds a folder to the collection of ProjectItems with the given name.
///
/// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder.
/// Virtual folders are not supported by this implementation.
/// </summary>
/// <param name="name">The name of the new folder to add</param>
/// <param name="kind">A string representing a Guid of the folder kind.</param>
/// <returns>A ProjectItem representing the newly added folder.</returns>
public override ProjectItem AddFolder(string name, string kind) {
Project.CheckProjectIsValid();
//Verify name is not null or empty
VsUtilities.ValidateFileName(this.Project.ProjectNode.Site, name);
//Verify that kind is null, empty, or a physical folder
if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) {
throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind");
}
var existingChild = this.NodeWithItems.FindImmediateChildByName(name);
if (existingChild != null) {
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name));
}
ProjectNode proj = this.Project.ProjectNode;
HierarchyNode newFolder = null;
using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) {
//In the case that we are adding a folder to a folder, we need to build up
//the path to the project node.
name = Path.Combine(NodeWithItems.FullPathToChildren, name);
newFolder = proj.CreateFolderNodes(name);
}
return newFolder.GetAutomationObject() as ProjectItem;
}
/// <summary>
/// Copies a source file and adds it to the project.
/// </summary>
/// <param name="filePath">The path and file name of the project item to be added.</param>
/// <returns>A ProjectItem object. </returns>
public override EnvDTE.ProjectItem AddFromFileCopy(string filePath) {
return this.AddItem(filePath, VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE);
}
/// <summary>
/// Adds a project item from a file that is installed in a project directory structure.
/// </summary>
/// <param name="fileName">The file name of the item to add as a project item. </param>
/// <returns>A ProjectItem object. </returns>
public override EnvDTE.ProjectItem AddFromFile(string fileName) {
// TODO: VSADDITEMOP_LINKTOFILE
return this.AddItem(fileName, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE);
}
#endregion
#region helper methods
/// <summary>
/// Adds an item to the project.
/// </summary>
/// <param name="path">The full path of the item to add.</param>
/// <param name="op">The <paramref name="VSADDITEMOPERATION"/> to use when adding the item.</param>
/// <returns>A ProjectItem object. </returns>
protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) {
CheckProjectIsValid();
return UIThread.Instance.RunSync<EnvDTE.ProjectItem>(() => {
string ext = Path.GetExtension(path);
foreach (var extension in this.Project.ProjectNode.CodeFileExtensions) {
// http://pytools.codeplex.com/workitem/617
// We are currently in create project from existing code mode. The wizard walks all of the top-level
// files and adds them. It then lets us handle any subdirectories by calling AddFromDirectory.
// But we want to filter the files for both top-level and subdirectories. Therefore we derive from
// PageManager and track when we're running the wizard and adding files for the wizard. If we are
// currently adding them ignore anything other than a .py/.pyw files - returnning null is fine
// here, the wizard doesn't care about the result.
if (String.Compare(ext, extension, StringComparison.OrdinalIgnoreCase) == 0) {
ProjectNode proj = this.Project.ProjectNode;
EnvDTE.ProjectItem itemAdded = null;
using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) {
VSADDRESULT[] result = new VSADDRESULT[1];
ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result));
string fileName = System.IO.Path.GetFileName(path);
string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems);
string filePathInProject = System.IO.Path.Combine(fileDirectory, fileName);
itemAdded = this.EvaluateAddResult(result[0], filePathInProject);
}
return itemAdded;
}
}
return null;
});
}
/// <summary>
/// Evaluates the result of an add operation.
/// </summary>
/// <param name="result">The <paramref name="VSADDRESULT"/> returned by the Add methods</param>
/// <param name="path">The full path of the item added.</param>
/// <returns>A ProjectItem object.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
private EnvDTE.ProjectItem EvaluateAddResult(VSADDRESULT result, string path) {
return UIThread.Instance.RunSync<EnvDTE.ProjectItem>(() => {
if (result == VSADDRESULT.ADDRESULT_Success) {
if (Directory.Exists(path) && !CommonUtils.HasEndSeparator(path)) {
path = path + Path.DirectorySeparatorChar;
}
HierarchyNode nodeAdded = this.NodeWithItems.ProjectMgr.FindNodeByFullPath(path);
Debug.Assert(nodeAdded != null, "We should have been able to find the new element in the hierarchy");
if (nodeAdded != null) {
EnvDTE.ProjectItem item = null;
if (nodeAdded is FileNode) {
item = new OAFileItem(this.Project, nodeAdded as FileNode);
} else {
item = new OAProjectItem(this.Project, nodeAdded);
}
return item;
}
}
return null;
});
}
#endregion
}
}